aligned the authentication with quantopian.com standard

This commit is contained in:
fawce
2012-01-09 14:50:34 -05:00
parent 2860328897
commit d39604847d
2 changed files with 136 additions and 1 deletions
+27 -1
View File
@@ -1,3 +1,29 @@
# Quantopian Backtesting Services
# qbt - Quantopian Backtesting Services
qbt uses tornado to accept synchronous requests for backtesting sessions.
The client of a backtesting session first invokes the _backtest_ endpoint:
http://serverip/backtest?startdate=<>&enddate=<>...
qbt will respond with a json object describing the session:
- backtest id, to be referenced in all further requests
- zeromq connection information for the event stream
A backtesting session is comprised of:
- REST endpoint to request orders
- an event stream delivered via zeromq
## Pre-requisites
### MongoDB Server ###
QBT requires a running mongodb instance with a few collections:
- user collection. See handlers.BaseHandler for code using this collection. Documents must have:
- email - standard email address
- encrypted_password - an sha2 hex digest of the password
- salt - a secret other than the password, which can be set in a secure cookie to maintain a session. if unset, will be set to sha2 hex of datetime.utcnow()--password
- _id - standard issue mongodb primary key
## Requesting a Backtest
+109
View File
@@ -0,0 +1,109 @@
import tornado.auth
import tornado.httpserver
import tornado.ioloop
from tornado.options import define, options
import tornado.web
import pymongo
import bson
import hashlib
import base64
import uuid
import os
import logging
logging.getLogger('qbt').setLevel(logging.DEBUG)
logger = logging.getLogger('qbt')
define("port", default=8888, help="run the qbt on the given port", type=int)
define("mongodb_host", default="127.0.0.1", help="mongodb host address")
define("mongodb_port", default=27017, help="connect to the mongodb on the given port", type=int)
define("mongodb_dbname", default="blog", help="database name")
define("mongodb_user", default="blog", help="database user")
define("mongodb_password", default="blog", help="database password")
HASH_ALGO = 'sha256'
class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/", MainHandler),
(r"/login", LoginHandler),
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static"),
xsrf_cookies=False,
cookie_secret=base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes),
login_url="/login",
#autoescape=None,
debug=True,
)
tornado.web.Application.__init__(self, handlers, **settings)
# Have one global connection to the blog DB across all handlers
self.connection = pymongo.Connection(options.mongodb_host, options.mongodb_port)
self.db = self.connection[options.mongodb_dbname]
self.db.authenticate(options.mongodb_user, options.mongodb_password)
class BaseHandler(tornado.web.RequestHandler):
@property
def db(self):
return self.application.db
def get_current_user(self):
user_id = self.get_secure_cookie(u"user_id")
logger.info("looking up user with id: {id}".format(id=user_id))
if not user_id: return None
#get user record by id
users = self.db.users.find(spec={"_id":bson.ObjectId(user_id)}, limit=1)
if(users.count > 0):
return users[0]
return None
class MainHandler(BaseHandler):
@tornado.web.authenticated
def get(self):
self.write("Hello, world")
class LoginHandler(BaseHandler):
def get(self):
self.write('<html><body><form action="/login" method="post">'
'Name: <input type="text" name="user_name">'
'pass: <input type="password" name="password">'
'<input type="submit" value="Sign in">'
'</form></body></html>')
def post(self):
self.authenticate(self.get_argument("user_name"),self.get_argument("password"))
self.redirect("/")
def authenticate(self, username, password):
h = hashlib.new(HASH_ALGO)
#find user record by username.
users = self.db.users.find(spec={"email":username}, limit=1)
if(users.count > 0):
user_record = users[0]
else:
logger.debug("no user with name: {username}", username=username)
return
#calculate password hash
h.update(user_record['salt']+"--"+password)
encrypted_password = h.hexdigest()
logger.debug("checking {password} as {encrypted_password} against {record}".format(password=password, encrypted_password=encrypted_password, record=user_record['encrypted_password']))
if (user_record['encrypted_password'] == encrypted_password):
#we have a match, so set the secure cookie to the salt
logger.debug("setting user_id cookie to {id}".format(id=user_record['_id']))
self.set_secure_cookie(u"user_id", unicode(user_record['_id']))
def main():
tornado.options.parse_command_line()
http_server = tornado.httpserver.HTTPServer(Application())
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()