While working on Baralbait's API - yes, we may have an API someday, and you can sure contact us if you need to know more about it. Anyway, while developing the API, we were planning to use CherryPy Basic Authentication, in order to authenticate the API Calls.
This is how to add CherryPy Basic Authentication to one of your methods/pages:
import cherrypy users = {"user1": "secret1", "user2": "secret2"} def clear_text(mypass): return mypass class MyServer: def index(self): return "This is a public page!" index.exposed = True def secret(self) print "Logged user is:", cherrypy.request.login return "Awesome, you've just accessed a page that requires HTTP Basic Authentication" secret.exposed = True secret._cp_config = {'tools.basic_auth.on': True, 'tools.basic_auth.realm': 'My Secure Server', 'tools.basic_auth.users': users, 'tools.basic_auth.encrypt': clear_text} if __name__ == '__main__': cherrypy.quickstart(MyServer(),"/","myserver.conf")
The above code means, that the page called "index", is a public page, while "secret" requires HTTP Basic Authentication, with the credentials mentioned in the "users" dictionary. For more info, Jim Hoskins has an awesome tutorial about using HTTP Basic Authentication in CherryPy, however his site is down now :(
Now, the problem with the above code, is that you can either make a certain page public or secured, but you cannot make it public and private in the same time. Ok, please be patient, let's say that you want authenticated users to see certain content when visiting our secret page, while unauthenticated users should see different content instead of being blocked. For example, we want authenticated users to see their friend's news feed, while unauthenticated users see public news.
So, here comes the beauty of CherryPy Custom tools. You can now, build your own authentication hook, and make it return a null or custom user id when an incorrect or no username or password are given, instead of totally blocking the user.
And here are the modifications needed to the above code:
import cherrypy from cherrypy.lib import httpauth users = {"user1": "secret1", "user2": "secret2"} def clear_text(mypass): return mypass def my_basic_auth(realm, users, encrypt=None): if cherrypy.lib.auth.check_auth(users, encrypt): print "DEBUG: Authenticated" return else: print "DEBUG: Not Authenticated" cherrypy.request.login = "Anonymous" return class MyServer: def index(self): return "This is a public page!" index.exposed = True def secret(self) if cherrypy.request.login == "Anonymous": return "This is another public page on our useless website." else: return "Can you keep a secret, this page is really confidential." secret.exposed = True secret._cp_config = {'tools.my_basic_auth.on': True, 'tools.my_basic_auth.realm': 'My Secure Server', 'tools.my_basic_auth.users': users, 'tools.my_basic_auth.encrypt': clear_text} if __name__ == '__main__': cherrypy.tools.mybasic_auth = cherrypy.Tool('on_start_resource', my_basic_auth) cherrypy.quickstart(MyServer(),"/","myserver.conf")
So, we have just created a custom tool, and hooked it in the earliest hook ever, 'on_start_resource', i.e. during the request. We also created our own authentication method, 'my_basic_auth', and attached it to the tool. In our authentication method, which is almost identical to CherryPy's built in HTTP Basic Authentication method, however we do not raise any errors regardless the user is connected or not, we just set 'cherrypy.request.login' to an arbitrary user, that our application can understand later on, such as 'Anonymous'.
I was able to access Jim Hoskins's tutorial via waybackmachine.org :)
ReplyDeletehttp://replay.waybackmachine.org/20090222054041/http://jimhoskins.com/2008/07/21/cherrypy-digest-and-basic-authentication/
I think CherryPy is a useful method for implementing the authentication of API Calls. Thanks for such a helpful codes & information
ReplyDeleteRequesting a frob for the identification of the login session (call) requires a signature. This signature starts with the secret you shared that has to be followed by your API key.
ReplyDelete