config.plugins.Webinterface.enable = ConfigYesNo(default = True)
config.plugins.Webinterface.port = ConfigInteger(80,limits = (1, 999))
config.plugins.Webinterface.includehdd = ConfigYesNo(default = False)
+config.plugins.Webinterface.useauth = ConfigYesNo(default = True)
sessions = [ ]
use tail -f <file> to view this log
"""
-DEBUG = False
+DEBUG = True
DEBUGFILE= "/tmp/twisted.log"
-# Passwordprotection Test
-# set it only to True, if you have a patched wrapper.py
-# see http://twistedmatrix.com/trac/ticket/2041
-# in /usr/lib/python2.4/site-packages/twisted/web2/auth/wrapper.py
-# The solution is to change this line
-#
-# return self.authenticate(req), seg[1:]
-# into this
-# return self.authenticate(req), seg
-PASSWORDPROTECTION = False
-PASSWORDPROTECTION_pwd = "root"
-PASSWORDPROTECTION_mode = "sha";
-# twisted supports more than sha ('md5','md5-sess','sha')
-# but only sha works for me, but IE
-# sha, Firefox=ok, Opera=ok, wget=ok, ie=not ok
-# md5-sess, firefox=not ok, opera=not ok,wget=ok, ie=not ok
-# md5 same as md5-sess
+from twisted.cred.portal import Portal
+from twisted.cred import checkers
+from twisted.web2.auth import digest, basic, wrapper
+from zope.interface import Interface, implements
+from twisted.cred import portal
+from twisted.cred import credentials, error
+from twisted.internet import defer
+from zope import interface
+
def stopWebserver():
reactor.disconnectAll()
s=myProducerStream()
webif.renderPage(s, self.path, req, sessions[0]) # login?
return http.Response(responsecode.OK,{'Content-type': http_headers.MimeType('application', 'xhtml+xml', (('charset', 'UTF-8'),))},stream=s)
- #return http.Response(responsecode.OK,stream=s)
else:
return http.Response(responsecode.NOT_FOUND)
class Toplevel(resource.Resource):
addSlash = True
+ child_web = ScreenPage(util.sibpath(__file__, "web")) # "/web/*"
+ child_webdata = static.File(util.sibpath(__file__, "web-data")) # FIXME: web-data appears as webdata
def render(self, req):
fp = open(util.sibpath(__file__, "web-data")+"/index.html")
fp.close()
return http.Response(responsecode.OK, {'Content-type': http_headers.MimeType('text', 'html')},stream=s)
- child_web = ScreenPage(util.sibpath(__file__, "web")) # "/web/*"
- child_webdata = static.File(util.sibpath(__file__, "web-data")) # FIXME: web-data appears as webdata
- toplevel = Toplevel()
if config.plugins.Webinterface.includehdd.value:
toplevel.putChild("hdd",static.File("/hdd"))
- if PASSWORDPROTECTION is False:
- site = server.Site(toplevel)
+ if config.plugins.Webinterface.useauth.value is False:
+ site = server.Site(Toplevel())
else:
- from twisted.cred.portal import Portal
- from twisted.cred import checkers
- from twisted.web2.auth import digest, basic, wrapper
- from zope.interface import Interface, implements
- from twisted.cred import portal
- class IHTTPUser(Interface):
- pass
-
- class HTTPUser(object):
- implements(IHTTPUser)
-
- class HTTPAuthRealm(object):
- implements(portal.IRealm)
- def requestAvatar(self, avatarId, mind, *interfaces):
- if IHTTPUser in interfaces:
- return IHTTPUser, HTTPUser()
- raise NotImplementedError("Only IHTTPUser interface is supported")
-
portal = Portal(HTTPAuthRealm())
- checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(root=PASSWORDPROTECTION_pwd)
- portal.registerChecker(checker)
- root = wrapper.HTTPAuthResource(toplevel,
- (basic.BasicCredentialFactory('DM7025'),digest.DigestCredentialFactory(PASSWORDPROTECTION_mode,'DM7025')),
- portal, (IHTTPUser,))
+ portal.registerChecker(PasswordDatabase())
+ root = ModifiedHTTPAuthResource(Toplevel(),(basic.BasicCredentialFactory('DM7025'),),portal, (IHTTPUser,))
site = server.Site(root)
print "[WebIf] starting Webinterface on port",config.plugins.Webinterface.port.value
reactor.listenTCP(config.plugins.Webinterface.port.value, channel.HTTPFactory(site))
-
+
def autostart(reason, **kwargs):
if "session" in kwargs:
global sessions
def Plugins(**kwargs):
return [PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart),
PluginDescriptor(name=_("Webinterface"), description=_("Configuration for the Webinterface"),where = [PluginDescriptor.WHERE_PLUGINMENU], icon="plugin.png",fnc = openconfig)]
+
+
+class ModifiedHTTPAuthResource(wrapper.HTTPAuthResource):
+ """
+ set it only to True, if you have a patched wrapper.py
+ see http://twistedmatrix.com/trac/ticket/2041
+ so, the solution for us is to make a new class an override ne faulty func
+ """
+
+ def locateChild(self, req, seg):
+ return self.authenticate(req), seg
+
+class PasswordDatabase:
+ """
+ this checks webiflogins agains /etc/passwd
+ """
+ passwordfile = "/etc/passwd"
+ interface.implements(checkers.ICredentialsChecker)
+ credentialInterfaces = (credentials.IUsernamePassword,credentials.IUsernameHashedPassword)
+
+ def _cbPasswordMatch(self, matched, username):
+ if matched:
+ return username
+ else:
+ return failure.Failure(error.UnauthorizedLogin())
+
+ def requestAvatarId(self, credentials):
+ try:
+ if check_passwd(credentials.username,credentials.password,self.passwordfile) is True:
+ return defer.maybeDeferred(credentials.checkPassword,credentials.password).addCallback(self._cbPasswordMatch, str(credentials.username))
+ else:
+ return defer.fail(error.UnauthorizedLogin())
+ except Exception,e:
+ print e
+
+class IHTTPUser(Interface):
+ pass
+
+class HTTPUser(object):
+ implements(IHTTPUser)
+
+class HTTPAuthRealm(object):
+ implements(portal.IRealm)
+ def requestAvatar(self, avatarId, mind, *interfaces):
+ if IHTTPUser in interfaces:
+ return IHTTPUser, HTTPUser()
+ raise NotImplementedError("Only IHTTPUser interface is supported")
+
+
+import md5,time,string,crypt
+DES_SALT = list('./0123456789' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz')
+def getpwnam(name, pwfile=None):
+ """Return pasword database entry for the given user name.
+
+ Example from the Python Library Reference.
+ """
+
+ if not pwfile:
+ pwfile = '/etc/passwd'
+
+ f = open(pwfile)
+ while 1:
+ line = f.readline()
+ if not line:
+ f.close()
+ raise KeyError, name
+ entry = tuple(line.strip().split(':', 6))
+ if entry[0] == name:
+ f.close()
+ return entry
+
+def passcrypt(passwd, salt=None, method='des', magic='$1$'):
+ """Encrypt a string according to rules in crypt(3)."""
+ if method.lower() == 'des':
+ if not salt:
+ salt = str(whrandom.choice(DES_SALT)) + str(whrandom.choice(DES_SALT))
+ return crypt.crypt(passwd, salt)
+ elif method.lower() == 'md5':
+ return passcrypt_md5(passwd, salt, magic)
+ elif method.lower() == 'clear':
+ return passwd
+
+def check_passwd(name, passwd, pwfile=None):
+ """Validate given user, passwd pair against password database."""
+
+ if not pwfile or type(pwfile) == type(''):
+ getuser = lambda x,pwfile=pwfile: getpwnam(x,pwfile)[1]
+ else:
+ getuser = pwfile.get_passwd
+
+ try:
+ enc_passwd = getuser(name)
+ except (KeyError, IOError):
+ return 0
+ if not enc_passwd:
+ return 0
+ elif len(enc_passwd) >= 3 and enc_passwd[:3] == '$1$':
+ salt = enc_passwd[3:string.find(enc_passwd, '$', 3)]
+ return enc_passwd == passcrypt(passwd, salt=salt, method='md5')
+ else:
+ return enc_passwd == passcrypt(passwd, enc_passwd[:2])
+
+def _to64(v, n):
+ r = ''
+ while (n-1 >= 0):
+ r = r + DES_SALT[v & 0x3F]
+ v = v >> 6
+ n = n - 1
+ return r
+
+def passcrypt_md5(passwd, salt=None, magic='$1$'):
+ """Encrypt passwd with MD5 algorithm."""
+
+ if not salt:
+ salt = repr(int(time.time()))[-8:]
+ elif salt[:len(magic)] == magic:
+ # remove magic from salt if present
+ salt = salt[len(magic):]
+
+ # salt only goes up to first '$'
+ salt = string.split(salt, '$')[0]
+ # limit length of salt to 8
+ salt = salt[:8]
+
+ ctx = md5.new(passwd)
+ ctx.update(magic)
+ ctx.update(salt)
+
+ ctx1 = md5.new(passwd)
+ ctx1.update(salt)
+ ctx1.update(passwd)
+
+ final = ctx1.digest()
+
+ for i in range(len(passwd), 0 , -16):
+ if i > 16:
+ ctx.update(final)
+ else:
+ ctx.update(final[:i])
+
+ i = len(passwd)
+ while i:
+ if i & 1:
+ ctx.update('\0')
+ else:
+ ctx.update(passwd[:1])
+ i = i >> 1
+ final = ctx.digest()
+
+ for i in range(1000):
+ ctx1 = md5.new()
+ if i & 1:
+ ctx1.update(passwd)
+ else:
+ ctx1.update(final)
+ if i % 3: ctx1.update(salt)
+ if i % 7: ctx1.update(passwd)
+ if i & 1:
+ ctx1.update(final)
+ else:
+ ctx1.update(passwd)
+ final = ctx1.digest()
+
+ rv = magic + salt + '$'
+ final = map(ord, final)
+ l = (final[0] << 16) + (final[6] << 8) + final[12]
+ rv = rv + _to64(l, 4)
+ l = (final[1] << 16) + (final[7] << 8) + final[13]
+ rv = rv + _to64(l, 4)
+ l = (final[2] << 16) + (final[8] << 8) + final[14]
+ rv = rv + _to64(l, 4)
+ l = (final[3] << 16) + (final[9] << 8) + final[15]
+ rv = rv + _to64(l, 4)
+ l = (final[4] << 16) + (final[10] << 8) + final[5]
+ rv = rv + _to64(l, 4)
+ l = final[11]
+ rv = rv + _to64(l, 2)
+
+ return rv
+
+