TheBeege

MB-Server main.py

Feb 2nd, 2014
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.56 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. # Native Python imports
  4. import cgi
  5. import logging
  6. import logging.handlers
  7. import sys
  8. import simplejson
  9. import signal
  10. import ConfigParser
  11. #import MySQLdb as mdb
  12. from zope.interface import implements
  13. from datetime import datetime
  14.  
  15. # Twisted imports
  16. from twisted.cred import error as credError
  17. from twisted.cred.credentials import IUsernameHashedPassword, IUsernamePassword
  18. from twisted.cred.checkers import ICredentialsChecker
  19. from twisted.cred.portal import Portal, IRealm
  20. from twisted.enterprise import adbapi
  21. from twisted.internet import ssl, reactor
  22. from twisted.internet.defer import Deferred
  23. from twisted.web.http import HTTPChannel
  24. from twisted.web.guard import HTTPAuthSessionWrapper
  25. from twisted.web.guard import DigestCredentialFactory
  26. from twisted.web.guard import BasicCredentialFactory
  27. from twisted.web.server import Site
  28. from twisted.web.resource import Resource, IResource
  29.  
  30. # Our imports
  31. import gameplayLogic
  32. import utils
  33. import accountLogic
  34. from utils import MBLogAdapter
  35.  
  36. class Registration(Resource):
  37.   def render_POST(self, request):
  38.     logger = logging.getLogger('MB-Server.RegistrationResource')
  39.     #formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(thread)d - Registration - render_POST - %(message)s')
  40.     #for hand in logger.handlers:
  41.     #  hand.setFormatter(formatter)
  42.     logger = MBLogAdapter(logger, {'file': 'main.py', 'object': 'Registration', 'method': 'render_POST'})
  43.  
  44.     logger.debug('request="%s"', str(request))
  45.     username = cgi.escape(request.args['username'][0])
  46.     password = cgi.escape(request.args['password'][0])
  47.     email = cgi.escape(request.args['email'][0])
  48.  
  49.     logger.debug('username="%s" password="%s" email="%s"', username, password, email)
  50.  
  51.     output = accountLogic.registerUser(username, password, email)
  52.     response_text = str({ 'status': output })
  53.  
  54.     request.setHeader("content-type", "application/json")
  55.     request.setResponseCode(200)
  56.     logger.debug('returning response="%s"', response_text)
  57.     return response_text
  58.  
  59. # http://twistedmatrix.com/documents/current/core/examples/dbcred.py
  60. class DBCredentialsChecker(object):
  61.   implements(ICredentialsChecker)
  62.  
  63.   baseLogger = None
  64.  
  65.   def __init__(self, runQuery,
  66.       query="""
  67.      CALL checkLogin(%s);
  68.      """, customCheckFunc=None, caseSensitivePasswords=True):
  69.     """@param runQuery: This will be called to get the info from the db.
  70.       Generally, you'd want to create a L{twisted.enterprise.abdapi.ConnectionPool}
  71.       and pass its runQuery method here. Otherwise pass a function with the same prototype.
  72.       @type runQuery: C{callable}
  73.  
  74.       @param query: query used to authenticate user.
  75.       @type query: C{str}
  76.  
  77.       @param customCheckFunc: Use this if the passwords in the db are stored as hashed. We'll just call this, so you can do the checking yourself. It takes the following params: (username, suppliedPass, dbPass) and must return a boolean.
  78.       @type customCheckFunc: C{callable}
  79.  
  80.       @param caseSensitivePasswords: If true requires that every letter in C{credentials.password} is exactly the same case as its counterpart character in the database. This is only relevant if C{customCheckFunc} is not used.
  81.       @type caseSensitivePasswords: C{bool}
  82.    """
  83.  
  84.     self.baseLogger = logging.getLogger('MB-Server.DBCredentialsChecker')
  85.     logger = MBLogAdapter(self.baseLogger, {'file': 'main.py', 'object': 'DBCredentialsChecker', 'method': '__init__'})
  86.     logger.debug('Starting method...')
  87.     logger.debug('runQuery="%s" caseSensitivePasswords="%s" customCheckFunc="%s" query="%s"', str(runQuery), str(caseSensitivePasswords), str(customCheckFunc), str(query))
  88.    
  89.     self.runQuery = runQuery
  90.     self.caseSensitivePasswords = caseSensitivePasswords
  91.     self.customCheckFunc = customCheckFunc
  92.     # We can't support hashed password credentials if we only have a hash in the DB
  93.     if customCheckFunc:
  94.       self.credentialsInterfaces = (IUsernamePassword,)
  95.     else:
  96.       self.credentialInterfaces = (IUsernamePassword, IUsernameHashedPassword,)
  97.  
  98.     self.sql = query
  99.  
  100.   def requestAvatarId(self, credentials):
  101.     """
  102.    Authenticates the kiosk against the database.
  103.    """
  104.     logger = MBLogAdapter(self.baseLogger, {'file': 'main.py', 'object': 'DBCredentialsChecker', 'method': 'requestAvatarId'})
  105.     logger.debug('Starting method...')
  106.     logger.debug('credentials="%s"', str(credentials))
  107.     # Check that the credentials instance implements at least one of our interfaces
  108.     for interface in self.credentialInterfaces:
  109.       if interface.providedBy(credentials):
  110.         break
  111.       else:
  112.         raise credError.UnhandledCredentials()
  113.  
  114.     # Ask the database for the username and password
  115.     dbDeferred = self.runQuery(self.sql, (credentials.username,))
  116.     # Setup our deferred result
  117.     deferred = Deferred()
  118.     dbDeferred.addCallbacks(self._cbAuthenticate, self._ebAuthenticate,
  119.       callbackArgs=(credentials, deferred),
  120.       errbackArgs=(credentials, deferred))
  121.     return deferred
  122.  
  123.   def _cbAuthenticate(self, result, credentials, deferred):
  124.     """
  125.    Checks to see if the authentication was good. Called once the info has been retrieved from the DB.
  126.    """
  127.  
  128.     logger = MBLogAdapter(self.baseLogger, {'file': 'main.py', 'object': 'DBCredentialsChecker', 'method': '_cbAuthenticate'})
  129.     logger.debug('Starting method...')
  130.     logger.debug('result="%s" credentials="%s" deferred="%s"', str(result), str(credentials), str(deferred))
  131.     if len(result) == 0:
  132.       # Username not found in db
  133.       deferred.errback(credError.UnauthorizedLogin('Username unknown'))
  134.     else:
  135.       username, password = result[0]
  136.       if self.customCheckFunc:
  137.         # Let the owner do the checking
  138.         if self.customCheckFunc(
  139.             username, credentials.password, password):
  140.           deferred.callback(credentials.username)
  141.         else:
  142.           deferred.errback(credError.UnauthorizedLogin('Password mismatch'))
  143.       else:
  144.         # It's up to us or the credentials object to do the checking now
  145.         if IUsernameHashedPassword.providedBy(credentials):
  146.           # Let the hashed password checker do the checking
  147.           if credentials.checkPassword(password):
  148.             deferred.callback(credentials.username)
  149.           else:
  150.             deferred.errback(credError.UnauthorizedLogin('Password mismatch'))
  151.         elif IUsernamePassword.providedBy(credentials):
  152.           # Compare the passwords, deciding whether or not to use case sensitivity
  153.           if self.caseSensiivePasswords:
  154.             passOk = (password.lower() == credentials.password.lower())
  155.           else:
  156.             passOk = password == credentials.password
  157.  
  158.           # See if they match
  159.           if passOk:
  160.             deferred.callback(credentials.username)
  161.           else:
  162.             deferred.errback(credError.UnauthorizedLogin('Password mismatch'))
  163.         else:
  164.           # OK, we don't know how to check this
  165.           deferred.errback(credError.UnhandledCredentials())
  166.  
  167.   def _ebAuthenticate(self, message, credentials, deferred):
  168.     """
  169.    The database lookup failed for some reason.
  170.    """
  171.     logger = MBLogAdapter(self.baseLogger, {'file': 'main.py', 'object': 'DBCredentialsChecker', 'method': '_ebAuthenticate'})
  172.     logger.debug('Starting method...')
  173.     logger.debug('message="%s" credentials="%s" deferred="%s"', str(message), str(credentials), str(deferred))
  174.     deferred.errback(credError.LoginFailed(message))
  175.  
  176. #class PasswordChecker:
  177. #  implements(checkers.ICredentialsChecker)
  178. #  credentialInterfaces = (credentials.IUsernamePassword,)
  179. #
  180. #  def requestAvatarId(self, credentials):
  181. #    logger = logging.getLogger('MB-Server.PasswordChecker')
  182. #    logger = MBLogAdapter(logger, {'file': 'main.py', 'object': 'PasswordChecker', 'method': 'requestAvatarId'})
  183. #    username = credentials.username
  184. #    # check DB here
  185. #    
  186. #    if True:
  187. #      return defer.succeed(username)
  188. #    else:
  189. #      return defer.fail(credError.UnauthorizedLogin("bad creds"))
  190.  
  191.  
  192. class HttpPasswordRealm(object):
  193.   implements(IRealm)
  194.  
  195.   logger = None
  196.  
  197.   def __init__(self, myresource):
  198.     self.logger = logging.getLogger('MB-Server.HttpPasswordRealm')
  199.     self.logger = MBLogAdapter(self.logger, {'file': 'main.py', 'object': 'HttpPasswordRealm', 'method': '__init__'})
  200.     self.logger.info('Creating new HttpPasswordRealm')
  201.     self.myresource = myresource
  202.  
  203.   def requestAvatar(self, user, mind, *interfaces):
  204.     self.logger = MBLogAdapter(self.logger, {'file': 'main.py', 'object': 'HttpPasswordRealm', 'method': 'requestAvatar'})
  205.     self.logger.debug('requestAvatar(%s, %s, %s) called', str(user), str(mind), str(interface))
  206.     if IResource in interfaces:
  207.       self.logger.debug('IResource="%s"', str(IResource))
  208.      
  209.       # myresource is passed regardless of user
  210.       return (IResource, self.myresource, lambda: None)
  211.     raise NotImplementedError()
  212.  
  213. class MyResource(Resource):
  214.  
  215.   def __init__(self):
  216.     self.logger = logging.getLogger('MB-Server.MyResource')
  217.     self.logger = MBLogAdapter(self.logger, {'file': 'main.py', 'object': 'MyResource', 'method': '__init__'})
  218.     self.logger.info('Creating new HttpPasswordRealm')
  219.    
  220.     Resource.__init__(self)
  221.    
  222.   def getChild(self, path, request):
  223.     self.logger = MBLogAdapter(self.logger, {'file': 'main.py', 'object': 'MyResource', 'method': 'getChild'})
  224.     self.logger.debug('getChild(%s, %s) called', str(path), str(request))
  225.     text = "You're in. The path is /%s." % path
  226.     return static.Data(text, "text/plain")
  227.  
  228.  
  229. #class Login(Resource):
  230. #  def render_POST(self, request):
  231. #    logger = logging.getLogger('MB-Server.LoginResource')
  232. #    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(thread)d - Login - render_POST - %(message)s')
  233. #    for hand in logger.handlers:
  234. #      hand.setFormatter(formatter)
  235. #
  236. #    logger.debug('request="%s"', str(request))
  237. #    username = cgi.escape(request.args['username'][0])
  238. #    password = cgi.escape(request.args['password'][0])
  239. #    email = cgi.escape(request.args['email'][0])
  240. #
  241. #    logger.debug('username="%s" password="%s" email="%s"', username, password, email)
  242. #
  243. #    output = accountLogic.registerUser(username, password, email)
  244. #    response_text = str({ 'status': output })
  245. #
  246. #    request.setHeader("content-type", "application/json")
  247. #    request.setResponseCode(200)
  248. #    logger.debug('returning response="%s"', response_text)
  249. #    return response_text
  250.  
  251.  
  252.  
  253.  
  254. if __name__ == "__main__":
  255.   # Run Dat server
  256.  
  257.  
  258.   # CONFIGS
  259.   config = ConfigParser.RawConfigParser()
  260.   config.read('server.conf')
  261.  
  262.   PORT = int(config.get('server','port'))
  263.  
  264.   # LOGGING
  265.   log = logging.getLogger('MB-Server')
  266.   formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(thread)d - %(message)s')
  267.  
  268.   consoleHandler = logging.StreamHandler()
  269.   consoleHandler.setFormatter(formatter)
  270.   consoleHandler.setLevel(logging.DEBUG)
  271.   log.addHandler(consoleHandler)
  272.  
  273.   fileHandler = logging.handlers.RotatingFileHandler('log/server.log', maxBytes=52428800) # 50 MB files
  274.   fileHandler.setFormatter(formatter)
  275.   fileHandler.setLevel(logging.DEBUG)
  276.   log.addHandler(fileHandler)
  277.  
  278.   log.setLevel(logging.DEBUG)
  279.   log = MBLogAdapter(log, {'file': 'main.py', 'object': 'raw', 'method': 'init'})
  280.  
  281.   log.info('Server starting on port="%s"...', PORT)
  282.  
  283.   # SERVER SETUP
  284.   root = Resource()
  285.  
  286.   myresource = MyResource()
  287.  
  288.   pool = adbapi.ConnectionPool('MySQLdb',(config.get('database','host'),config.get('database','user'),config.get('database','password'),config.get('database','database')))
  289.  
  290.   #checker = PasswordChecker()
  291.   checker = DBCredentialsChecker(pool.runQuery, query="SELECT username, password FROM user WHERE username = ?")
  292.   #checker.requestAvatarId('my bogus data')
  293.   realm = HttpPasswordRealm(myresource)
  294.   p = Portal(realm)
  295.   p.registerChecker(checker)
  296.   log.debug('p="%s"', str(p))
  297.  
  298.   credentialFactory = BasicCredentialFactory("Chainsaw Rabbit Games")
  299.   log.debug('credentialFactory="%s"', str(credentialFactory))
  300.   protected_resource = HTTPAuthSessionWrapper(p, [credentialFactory])
  301.   log.debug('protected_resource="%s"', str(protected_resource))
  302.  
  303.   root.putChild('register', Registration())
  304.   root.putChild('example', protected_resource)
  305.   #root.putChild('login', Login())
  306.   factory = Site(root)
  307.   factory.protocol = HTTPChannel
  308.   #reactor.listenTCP(PORT, factory)
  309.   log.debug('listCredentialsInterfaces="%s"', str(p.listCredentialsInterfaces()))
  310.   reactor.listenSSL(PORT, factory,
  311.                     ssl.DefaultOpenSSLContextFactory(
  312.                       'ssl/server.key', 'ssl/server.crt'))
  313.   reactor.run()
Advertisement
Add Comment
Please, Sign In to add comment