<!DOCTYPE html> <html> <head> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script> <script> $(function() { var conn = null; function log(msg) { var control = $('#log'); control.html(control.html() + msg + '<br/>'); control.scrollTop(control.scrollTop() + 1000); } function connect() { disconnect(); var transports = $('#protocols input:checked').map(function(){ return $(this).attr('id'); }).get(); conn = new SockJS('http://' + window.location.host + '/chat', transports); log('Connecting...'); conn.onopen = function() { log('Connected.'); update_ui(); }; conn.onmessage = function(e) { log('Received: ' + e.data); }; conn.onclose = function() { log('Disconnected.'); conn = null; update_ui(); }; } function disconnect() { if (conn != null) { log('Disconnecting...'); conn.close(); conn = null; update_ui(); } } function update_ui() { var msg = ''; if (conn == null || conn.readyState != SockJS.OPEN) { $('#status').text('disconnected'); $('#connect').text('Connect'); } else { $('#status').text('connected (' + conn.protocol + ')'); $('#connect').text('Disconnect'); } } $('#connect').click(function() { if (conn == null) { connect(); } else { disconnect(); } update_ui(); return false; }); $('form').submit(function() { var text = $('#text').val(); log('Sending: ' + text); conn.send(text); $('#text').val('').focus(); return false; }); }); </script> </head> <body> <h3>Chat!</h3> <div id="protocols" style="float: right"> <ul> <li> <input id="websocket" type="checkbox" value="websocket" checked="checked"></input> <label for="websocket">websocket</label> </li> <li> <input id="xhr-streaming" type="checkbox" value="xhr-streaming" checked="checked"></input> <label for="xhr-streaming">xhr-streaming</label> </li> <li> <input id="iframe-eventsource" type="checkbox" value="iframe-eventsource" checked="checked"></input> <label for="iframe-eventsource">iframe-eventsource</label> </li> <li> <input id="iframe-htmlfile" type="checkbox" value="iframe-htmlfile" checked="checked"></input> <label for="iframe-htmlfile">iframe-htmlfile</label> </li> <li> <input id="xhr-polling" type="checkbox" value="xhr-polling" checked="checked"></input> <label for="xhr-polling">xhr-polling</label> </li> <li> <input id="iframe-xhr-polling" type="checkbox" value="iframe-xhr-polling" checked="checked"></input> <label for="iframe-xhr-polling">iframe-xhr-polling</label> </li> <li> <input id="jsonp-polling" type="checkbox" value="jsonp-polling" checked="checked"></input> <label for="jsonp-polling">jsonp-polling</label> </li> </ul> </div> <div> <a id="connect" href="#">Connect</a> | Status: <span id="status">disconnected</span> </div> <div id="log" style="width: 60em; height: 20em; overflow:auto; border: 1px solid black"> </div> <form id="chatform"> <input id="text" type="text" /> <input type="submit" /> </form> </body> </html>
Tornado and Friends
Asynchronous web Frameworks and Libraries for Python
Wednesday, May 28, 2014
SockJS-Tornado : chat example - html part
SockJS-Tornado : chat example.
# -*- coding: utf-8 -*- """ Simple sockjs-tornado chat application. By default will listen on port 8080. """ import tornado.ioloop import tornado.web import sockjs.tornado class IndexHandler(tornado.web.RequestHandler): """Regular HTTP handler to serve the chatroom page""" def get(self): self.render('index.html') class ChatConnection(sockjs.tornado.SockJSConnection): """Chat connection implementation""" # Class level variable participants = set() def on_open(self, info): # Send that someone joined self.broadcast(self.participants, "Someone joined.") # Add client to the clients list self.participants.add(self) def on_message(self, message): # Broadcast message self.broadcast(self.participants, message) def on_close(self): # Remove client from the clients list and broadcast leave message self.participants.remove(self) self.broadcast(self.participants, "Someone left.") if __name__ == "__main__": import logging logging.getLogger().setLevel(logging.DEBUG) # 1. Create chat router ChatRouter = sockjs.tornado.SockJSRouter(ChatConnection, '/chat') # 2. Create Tornado application app = tornado.web.Application( [(r"/", IndexHandler)] + ChatRouter.urls ) # 3. Make Tornado app listen on port 8080 app.listen(8080) # 4. Start IOLoop tornado.ioloop.IOLoop.instance().start()
Sunday, May 25, 2014
Tornado authentification example
https://github.com/contaconta/TornadoAuthTest
# -*- coding: utf-8 -*- ''' User: ogata Date: 5/31/12 Time: 2:10 PM ''' __author__ = 'ogata' import tornado.ioloop import tornado.web import tornado.escape import tornado.options from tornado.options import define, options import os import logging define("port", default=5000, type=int) define("username", default="user") define("password", default="pass") class Application(tornado.web.Application): def __init__(self): handlers = [ (r'/', MainHandler), (r'/auth/login', AuthLoginHandler), (r'/auth/logout', AuthLogoutHandler), ] settings = dict( cookie_secret='gaofjawpoer940r34823842398429afadfi4iias', static_path=os.path.join(os.path.dirname(__file__), "static"), template_path=os.path.join(os.path.dirname(__file__), "templates"), login_url="/auth/login", xsrf_cookies=True, autoescape="xhtml_escape", debug=True, ) tornado.web.Application.__init__(self, handlers, **settings) class BaseHandler(tornado.web.RequestHandler): cookie_username = "username" def get_current_user(self): username = self.get_secure_cookie(self.cookie_username) logging.debug('BaseHandler - username: %s' % username) if not username: return None return tornado.escape.utf8(username) def set_current_user(self, username): self.set_secure_cookie(self.cookie_username, tornado.escape.utf8(username)) def clear_current_user(self): self.clear_cookie(self.cookie_username) class MainHandler(BaseHandler): @tornado.web.authenticated def get(self): self.write("Hello, <b>" + self.get_current_user() + "</b> <br> <a href=/auth/logout>Logout</a>") class AuthLoginHandler(BaseHandler): def get(self): self.render("login.html") def post(self): logging.debug("xsrf_cookie:" + self.get_argument("_xsrf", None)) self.check_xsrf_cookie() username = self.get_argument("username") password = self.get_argument("password") logging.debug('AuthLoginHandler:post %s %s' % (username, password)) if username == options.username and password == options.password: self.set_current_user(username) self.redirect("/") else: self.write_error(403) class AuthLogoutHandler(BaseHandler): def get(self): self.clear_current_user() self.redirect('/') def main(): tornado.options.parse_config_file(os.path.join(os.path.dirname(__file__), 'server.conf')) tornado.options.parse_command_line() app = Application() app.listen(options.port) logging.debug('run on port %d in %s mode' % (options.port, options.logging)) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": main()
Saturday, May 24, 2014
Basic authentication on Tornado with a decorator
Quote from site
Tornado doesn’t provide a good documentation when you try to handle your own login service. I tried to do mine.My goal is to allow a user to access my web application when he has good permissions.
Friday, May 23, 2014
Tornado – XSRF
Quote from site
XSRF or CSRF or sea-surf is web security vulnerability that takes advantage of website’s trust in user. In this attack, the user is forced into performing unwanted activities on the website where s/he is logged in.
http://technobeans.wordpress.com/2012/08/31/tornado-xsrf/
XSRF or CSRF or sea-surf is web security vulnerability that takes advantage of website’s trust in user. In this attack, the user is forced into performing unwanted activities on the website where s/he is logged in.
http://technobeans.wordpress.com/2012/08/31/tornado-xsrf/
Tornado user authentication example
Another example from mehmetkose
https://github.com/mehmetkose/tornado-user-authentication-example/blob/master/app.py
https://github.com/mehmetkose/tornado-user-authentication-example/blob/master/app.py
import tornado.httpserver import tornado.ioloop import tornado.web import tornado.options import os.path from tornado.options import define, options define("port", default=8000, help="run on the given port", type=int) class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): return self.get_secure_cookie("user") class MainHandler(BaseHandler): @tornado.web.authenticated def get(self): self.render('index.html', user=self.current_user) class LoginHandler(BaseHandler): def get(self): self.render('login.html') def post(self): getusername = self.get_argument("username") getpassword = self.get_argument("password") if "demo" == getusername and "demo" == getpassword: self.set_secure_cookie("user", self.get_argument("username")) self.redirect("/") else: wrong=self.get_secure_cookie("wrong") if wrong==False or wrong == None: wrong=0 self.set_secure_cookie("wrong", str(int(wrong)+1)) self.write('Kullanici Adi veya Sifre Yanlis <a href="/login">Geri</a> '+str(wrong)) class LogoutHandler(BaseHandler): def get(self): self.clear_cookie("user") self.redirect(self.get_argument("next", "/")) class Application(tornado.web.Application): def __init__(self): base_dir = os.path.dirname(__file__) settings = { "cookie_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=", "login_url": "/login", 'template_path': os.path.join(base_dir, "templates"), 'static_path': os.path.join(base_dir, "static"), 'debug':True, "xsrf_cookies": True, } tornado.web.Application.__init__(self, [ tornado.web.url(r"/", MainHandler, name="main"), tornado.web.url(r'/login', LoginHandler, name="login"), tornado.web.url(r'/logout', LogoutHandler, name="logout"), ], **settings) def main(): tornado.options.parse_command_line() Application().listen(options.port) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": main()
Tornado authentication best practice
Here is an extract of the Google group discussion
https://groups.google.com/forum/#!msg/python-tornado/ty8Xerv0ALc/IQRMM9n_4agJ
Response from Ben:
I think the author's argument against persistent login is misplaced; persistent login cookies are compatible with the security needs of most sites. However, the points he make here are valid and are best practices be followed whether your login cookies are persistent or not. (Tornado's example apps don't do this. I'd like to do a better job of steering people towards best practices, but I also don't want to overwhelm the simple examples with complex login functionality).
https://groups.google.com/forum/#!msg/python-tornado/ty8Xerv0ALc/IQRMM9n_4agJ
Response from Ben:
I think the author's argument against persistent login is misplaced; persistent login cookies are compatible with the security needs of most sites. However, the points he make here are valid and are best practices be followed whether your login cookies are persistent or not. (Tornado's example apps don't do this. I'd like to do a better job of steering people towards best practices, but I also don't want to overwhelm the simple examples with complex login functionality).
Specifically, you should store a random session key for each user in your database and include this session key in your signed cookies. The session key would be deleted or reset to a new random value when the user explicitly logs out or changes their password, and cookies would be rejected if they didn't have the right session key.
Storing only a hash of the session key in the database is a good idea, although this means that you have to have a one-to-many relationship between users and session keys (unless you want a login on one browser to invalidate any current logins on other browsers), since you won't be able to reuse the previous session key the next time the user logs in. The recommendation to use bcrypt or equivalent is kind of silly, though - a sufficiently large random session key cannot be brute forced even if the hash is a fast one, so just use your preferred SHA-family hash (bcrypt and friends are for when you're using low-entropy keys so that humans can remember them). Also note that it's important to use a good cryptographic random number generator (e.g. os.urandom instead of anything from the python stdlib's random module).
Server-side session keys ensure that even if a cookie is stolen (which can happen for non-persistent cookies too) it can be invalidated as soon as the user logs out, instead of being usable until it expires. Hashing the session keys in the database means that even an attacker who has read-only access to your database and a copy of your cookie-signing key cannot forge login cookies for arbitrary users.
-Ben
Tornado - Authentication
Quote from site :
Tornado provides get_current_user() method to determine if the user is already logged in. Developers need to override this method to get the current user and that can be done through cookies (secure). Every logged-in user, is represented by Tornado as self.current_user. By default this value is set to None.
http://technobeans.wordpress.com/2012/08/14/tornado-authentication/
Tornado provides get_current_user() method to determine if the user is already logged in. Developers need to override this method to get the current user and that can be done through cookies (secure). Every logged-in user, is represented by Tornado as self.current_user. By default this value is set to None.
http://technobeans.wordpress.com/2012/08/14/tornado-authentication/
import tornado.ioloop import tornado.web class Main(tornado.web.RequestHandler): def get_current_user(self): return self.get_secure_cookie("user") def get(self): if not self.current_user: self.redirect("/login") return username = self.current_user self.write('Hi there, '+ username) class Login(Main): def get(self): self.render('auth.html') def post(self): self.set_secure_cookie("user", self.get_argument("username")) self.redirect("/") application = tornado.web.Application([ (r"/", Main), (r"/login", Login), (r"/(style\.css)",tornado.web.StaticFileHandler, {"path": "./css/"}), ],debug=True, cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=") if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
Tornado Sqlite3
Quote fom site :
It allows you to build Tornado apps that work with SQLite3 using the same API that Tornado provides in its database module.
https://github.com/shamiksharma/tornado_sqlite3
Tornado-Subprocess
Quote from site :
A module which allows you to spawn subprocesses from a tornado web application in a non-blocking fashion.
https://github.com/vukasin/tornado-subprocess
Example:
A module which allows you to spawn subprocesses from a tornado web application in a non-blocking fashion.
https://github.com/vukasin/tornado-subprocess
Example:
def print_res( status, stdout, stderr, has_timed_out ) : if status == 0: print "OK:" print stdout else: print "ERROR:" print stderr t = Subprocess( print_res, timeout=30, args=[ "cat", "/etc/passwd" ] ) t.start() #start tornado t.ioloop.start()
Tornado WebServices
Quote from site :
This is an implementation of SOAP Web Service API, to be used in a Tornado Web Server, taking advantage of the great features of that server.
https://github.com/rancavil/tornado-webservices
Example : MathService.py
This is an implementation of SOAP Web Service API, to be used in a Tornado Web Server, taking advantage of the great features of that server.
https://github.com/rancavil/tornado-webservices
Example : MathService.py
#!/usr/bin/env python # # Copyright 2011 Rodrigo Ancavil del Pino # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import tornado.httpserver import tornado.ioloop from tornadows import soaphandler from tornadows import webservices from tornadows import xmltypes from tornadows.soaphandler import webservice class MathService(soaphandler.SoapHandler): """ Service that provides math operations of two float numbers """ @webservice(_params=[float,float],_returns=float) def add(self, a, b): result = a+b return result @webservice(_params=[float,float],_returns=float) def sub(self, a, b): result = a-b return result @webservice(_params=[float,float],_returns=float) def mult(self, a, b): result = a*b return result @webservice(_params=[float,float],_returns=float) def div(self, a, b): result = a/b return result if __name__ == '__main__': service = [('MathService',MathService)] app = webservices.WebService(service) ws = tornado.httpserver.HTTPServer(app) ws.listen(8080) tornado.ioloop.IOLoop.instance().start()
An example of Auth using Tornado + Motor
Tips from by Yutong Zhao on Google group
https://groups.google.com/forum/#!topic/python-tornado/l8slxrWHq-c
https://groups.google.com/forum/#!topic/python-tornado/l8slxrWHq-c
import tornado.testing import tornado.web import tornado.httpserver import motor import functools import pymongo def authenticate(method): @tornado.gen.coroutine @functools.wraps(method) def wrapper(self, *args, **kwargs): key = self.request.headers['Authorization'] query = {'token': key} cursor = self.application.db.users.admins result = yield cursor.find_one(query, {'_id': 1}) if not result: self.set_status(401) return self.write('Unauthorized') else: return method(self, *args, **kwargs) return wrapper class GetCurrentUser(tornado.web.RequestHandler): @tornado.gen.coroutine def get(self): current_user = yield self.get_current_user() print('Current user:', current_user) @tornado.gen.coroutine def get_current_user(self): key = self.request.headers['Authorization'] query = {'token': key} cursor = self.application.db.users.admins result = yield cursor.find_one(query, {'_id': 1}) if result: return result['_id'] else: return None class GetDecoratedUser(tornado.web.RequestHandler): @authenticate def get(self): print('Success') class TestCase(tornado.testing.AsyncHTTPTestCase): def setUp(self): db = pymongo.MongoClient() db.users.admins.insert({'_id': 'bob', 'token': '12345'}) super(TestCase, self).setUp() def tearDown(self): db = pymongo.MongoClient() db.users.admins.remove({}) super(TestCase, self).tearDown() def get_app(self): app = tornado.web.Application([ (r'/current_user', GetCurrentUser), (r'/decorator', GetDecoratedUser) ]) app.db = motor.MotorClient() return app def test_get_current_user(self): self.fetch('/current_user', headers={'Authorization': '12345'}) self.fetch('/current_user', headers={'Authorization': '54321'}) def test_decorator(self): self.fetch('/decorator', headers={'Authorization': '12345'}) self.fetch('/decorator', headers={'Authorization': '54321'})
Thursday, May 22, 2014
Method-based URL dispatcher for the Tornado web server
Nice tip which allows to write methods instead of class for requestHandler
Method-based URL dispatcher for the Tornado web server
Here is the classic way
The MethodDispatcher way
Highlighted with : http://tohtml.com/python/
Method-based URL dispatcher for the Tornado web server
Here is the classic way
class Foo(tornado.web.RequestHandler): def get(self): self.write('foo') class Bar(tornado.web.RequestHandler): def get(self): self.write('bar') class SimonSays(tornado.web.RequestHandler): def get(self): say = self.get_argument("say") self.write('Simon says, %s' % `say`) application = tornado.web.Application([ (r"/foo", Foo), (r"/bar", Bar), (r"/simonsays", SimonSays), ])
The MethodDispatcher way
class FooBar(MethodDispatcher): def foo(self): self.write("foo") def bar(self): self.write("bar") def simonsays(self, say): self.write("Simon Says, %s" % `say`) application = tornado.web.Application([ (r"/.*", FooBar) ])
Highlighted with : http://tohtml.com/python/
webservice-notifications
Quote from site :
webservice-notification
A server to plug into your own system, to create a notification system between some server side event, and your users. This aims to provide something close to what you can found on facebook (for example), with a small footprint on your existing architecture and client.
Subscribe to:
Posts (Atom)