解决ubuntu下twistd xxx --auth unix出现验证错误

测试了一下,在centos也是有效的。

首先给出程序的源代码。。使用twisted的plugin功能实现一个echo和远程执行命令的服务端:

 

 

#!/usr/bin/env python
#coding:utf8
# Author          : tuxpy
# Email           : q8886888@qq.com
# Last modified   : 2014-08-31 10:37:58
# Filename        : tw_cred.py
# Description     : 
from zope.interface import implements,Interface,implementer
from twisted.cred import checkers,credentials,portal
from twisted.internet import protocol,reactor
 
from twisted.protocols import basic
 
class IProtocolAvatar(Interface):
    def logout():
        """
        clean up per-login resources ollocated to this avator.
        """
    
 
 
 
class Avatar(object):
    implements(IProtocolAvatar)
 
    def logout(self):
        self.transport.loseConnection()
 
class EchoAvatar(Avatar):
    pass
 
class DoAvatara(Avatar):
 
    def do_comm(self,cmd,*args):
        from twisted.internet import utils
        output=utils.getProcessOutput(cmd,args=args,
                errortoo=True)
        output.addCallback(self.writeResponse)
 
    def writeResponse(self,result):
        self.transport.write(result)
 
 
 
class Echo(basic.LineReceiver):
    protal=None
    avatar=None
    logout=None
    delimiter='\n'
 
    def cocnnectionLost(self,reason):
        if self.logout:
            self.logout()
            self.avater=None
            seslf.logout=None
 
    def lineReceived(self,line):
        if not self.avatar:
            username,password=line.strip().split(" ")+[]
            self.tryLogin(username,password)
        else:
            if line.lower().strip()=='quit':
                self.avatar.logout()
            try:
                line=line.strip()
                cmd_parser=line.split(' ',1)
                if len(cmd_parser)>1:
                    cmd=cmd_parser[0]
                    args=cmd_parser[1:]
                else:
                    cmd,args=cmd_parser[0],tuple()
                self.avatar.do_comm(cmd.strip(),*args)
            except AttributeError,e:
                self.sendLine(line)
 
 
    def tryLogin(self,username,password):
        self.portal.login(credentials.UsernamePassword(username,
            password),
            None,IProtocolAvatar).addCallbacks(self._cbLogin,
                    self._ebLogin)
 
    def _cbLogin(self,(interface,avatar,logout)):
        self.avatar=avatar
        self.logout=logout
        self.avatar.transport=self.transport
        self.sendLine("Login successful,please procees.")
 
    def _ebLogin(self,failure):
        self.sendLine("Login denied,goodbye.")
     #   print failure
        self.transport.loseConnection()
 
class EchoFactory(protocol.Factory):
    def __init__(self,portal):
        self.portal=portal
 
    def buildProtocol(self,addr):
        protocol=Echo()
        protocol.portal=self.portal
        return protocol
        
class Realm(object):
    implements(portal.IRealm)
    
    def requestAvatar(self,avatarId,mind,*interfaces):
        if avatarId=='root':
            avatar=DoAvatara()
        else:
            avatar=EchoAvatar()
        return None,avatar,avatar.logout
 
        raise NotImplementedError("This realm only supports the IProtocolAvatar interface.")

插件文件:gedit  twisted/plugins/echo.py

#!/usr/bin/env python
#coding:utf8
# Author          : tuxpy
# Email           : q8886888@qq.com
# Last modified   : 2014-08-31 11:20:44
# Filename        : twisted/plugins/echo.py
# Description     : 
from twisted.application import internet,service
from twisted.plugin import IPlugin
from twisted.cred import credentials,portal,strcred
import sys
import os
sys.path.append(os.getcwd())
from tw_cred import EchoFactory,Realm
 
from twisted.python import usage
from zope.interface import implements
 
class Options(usage.Options,strcred.AuthOptionMixin):
    supportedInterfaces=(credentials.IUsernamePassword,)
    optParameters=[
            ["port",'p',1234,"The port number to listen on."]
            ]
 
class EchoServiceMaker(object):
    implements(service.IServiceMaker,IPlugin)
    tapname="echo"
    description="A TCP-base echo server."
    options=Options
 
    def makeService(self,options):
        p=portal.Portal(Realm(),options["credCheckers"])
        return internet.TCPServer(int(options['port']),EchoFactory(p))
serviceMaker=EchoServiceMaker()

启动:sudo twistd -n echo --auth unix -p 1235(为什么要用sudo,后面看cred_unix.py源代码中就会明白的)

但是这样启动好的话,按 书上说,我可以使用用户名和密码来验证,但是我怎么也验证不通过。因为我们的Options继承了strcred.AuthOptionMixin,同时我们又指定了credentials.IUsernamePassword接口,所以我们的插件会实现cred_*的那些checkers。于是查看twisted源代码。

 twisted/plugins/cred_unix.py

# -*- test-case-name: twisted.test.test_strcred -*-
#
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Cred plugin for UNIX user accounts.
"""
from zope.interface import implements
from twisted import plugin
from twisted.cred.strcred import ICheckerFactory
from twisted.cred.checkers import ICredentialsChecker
from twisted.cred.credentials import IUsernamePassword
from twisted.cred.error import UnauthorizedLogin
from twisted.internet import defer
def verifyCryptedPassword(crypted, pw):
    if crypted[0] == '$': # md5_crypt encrypted
        salt = '$1$' + crypted.split('$')[2]
    else:
        salt = crypted[:2]
    try:
        import crypt
    except ImportError:
        crypt = None
    if crypt is None:
        raise NotImplementedError("cred_unix not supported on this platform")
    return crypt.crypt(pw, salt) == crypted
class UNIXChecker(object):
    """
    A credentials checker for a UNIX server. This will check that
    an authenticating username/password is a valid user on the system.
    Does not work on Windows.
    Right now this supports Python's pwd and spwd modules, if they are
    installed. It does not support PAM.
    """
    implements(ICredentialsChecker)
    credentialInterfaces = (IUsernamePassword,)
    def checkPwd(self, pwd, username, password):
        try:
            cryptedPass = pwd.getpwnam(username)[1]
        except KeyError:
            return defer.fail(UnauthorizedLogin())
        else:
            if cryptedPass in ('*', 'x'):
                # Allow checkSpwd to take over
                return None
            elif verifyCryptedPassword(cryptedPass, password):
                return defer.succeed(username)
    def checkSpwd(self, spwd, username, password):
        try:
            cryptedPass = spwd.getspnam(username)[1]
        except KeyError:
            return defer.fail(UnauthorizedLogin())
        else:
            if verifyCryptedPassword(cryptedPass, password):
                return defer.succeed(username)
    def requestAvatarId(self, credentials):
        username, password = credentials.username, credentials.password
        try:
            import pwd
        except ImportError:
            pwd = None
        if pwd is not None:
            checked = self.checkPwd(pwd, username, password)
            if checked is not None:
                return checked
        try:
            import spwd
        except ImportError:
            spwd = None
        if spwd is not None:
            checked = self.checkSpwd(spwd, username, password)
            if checked is not None:
                return checked
        # TODO: check_pam?
        # TODO: check_shadow?
        return defer.fail(UnauthorizedLogin())
unixCheckerFactoryHelp = """
This checker will attempt to use every resource available to
authenticate against the list of users on the local UNIX system.
(This does not support Windows servers for very obvious reasons.)
Right now, this includes support for:
  * Python's pwd module (which checks /etc/passwd)
  * Python's spwd module (which checks /etc/shadow)
Future versions may include support for PAM authentication.
"""
class UNIXCheckerFactory(object):
    """
    A factory for L{UNIXChecker}.
    """
    implements(ICheckerFactory, plugin.IPlugin)
    authType = 'unix'
    authHelp = unixCheckerFactoryHelp
    argStringFormat = 'No argstring required.'
    credentialInterfaces = UNIXChecker.credentialInterfaces
    def generateChecker(self, argstring):
        """
        This checker factory ignores the argument string. Everything
        needed to generate a user database is pulled out of the local
        UNIX environment.
        """
        return UNIXChecker()
theUnixCheckerFactory = UNIXCheckerFactory()

verifyCryptedPassword函数中,也许是因为加密方式的不同,这样的验证会出现问题。只需要把verifyCryptedPassword函数改成这样,就能使用本地的username password验证了。。

 

def verifyCryptedPassword(crypted, pw):
    import platform
    if crypted[0] == '$': # md5_crypt encrypted
        if platform.system().lower() == "linux":
            salt = crypted
        else:
            salt = '$1$' + crypted.split('$')[2]
    else:
        salt = crypted[:2]
    try:
        import crypt
    except ImportError:
        crypt = None
 
    if crypt is None:
        raise NotImplementedError("cred_unix not supported on this platform")
    return crypt.crypt(pw, salt) == crypted




刚才在执行twistd时,为什么要加sudo?

通过源代码也可以看出,当pwd模块无法取得“密码”时,会使用spwd模块,而spwd模块是需要操作/etc/shadow文件,这个文件一般情况下,普通用户是没有读取权限的。spwd 会出现找不到用户的异常。



转载于:https://my.oschina.net/tuxpy/blog/308454

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值