posted on: 2009-10-27 18:48:38
I took the cherrypy wsgi server and setup a basic and digest authentication scheme. Works great.
>This is a very basic setup and I doubt it is much different then the one that comes with python. I start with cherrypy wsgi server, not the whole server. Then I parse the wsgi environ and perform http authentication.
Here is the code
#!/usr/bin/env python
"""
This file is minimal techniques to get both types of athentication through a simple wsgi server
mos likely this should be delegated to classes, but I have not done that since all I wanted to
make is a simple example, that uses both types of authentication.
I started with the example in CherryPy WSGI stand alone server.
"""
import CherryPyWSGI as cwsgi
import base64
from hashlib import md5
def my_crazy_app(environ, start_response):
"""Root directory no authenticaion"""
status = '200 OK'
response_headers = [('Content-type','text/plain')]
start_response(status, response_headers)
return ['Hello world!\n']
def my_basic_app(environ, start_response):
"""This basic authenticated file"""
status = '200 OK'
response_headers = [('Content-type','text/html')]
start_response(status, response_headers)
return ['<html><body><p>This is there the webpages go</p></body></html>']
def authenticate_basic_app(environ,start_response):
"""Performs the authentcation"""
auth_response = environ.get("HTTP_AUTHORIZATION","none:none")
name,passwd = getBasicCredentials(auth_response)
if passwd==getBasicPassword(name):
ret_value = my_basic_app(environ,start_response)
print passwd, getBasicPassword(name)
else:
print passwd, getBasicPassword(name)
ret_value = basicAuthenticationFailed(environ,start_response)
return ret_value
def getBasicCredentials(both):
"""Parses the HTTP_AUTHORIZATION item for basic credentials"""
encd = both.split()[-1]
values = base64.b64decode(encd).split(':')
if len(values)==2:
return values[0],values[1]
return "none","none"
def getBasicPassword(user):
"""Dummy function for getting a pasword"""
return "dogs"
def basicAuthenticationFailed(environ,start_response):
"""Failed authentication"""
status = '401 Unauthorized'
response_headers = [('WWW-Authenticate','basic realm="Secure Area"'),('Content-type','text/html')]
start_response(status,response_headers)
return ["<html><body>Authorization has failed</body></html>"]
def authenticate_digest_app(environ,start_response):
"""This begins the digest authentication process"""
auth_response = environ.get("HTTP_AUTHORIZATION","none")
data = getDigestCredentials(auth_response)
data['method'] = environ.get('REQUEST_METHOD')
if getDigestResponse(data):
ret_value = my_digest_app(environ,start_response)
else:
ret_value = digestAuthenticationFailed(environ,start_response)
return ret_value
def getDigestCredentials(auth_response):
"""Parses the return values from 'HTTP_AUHORIZATION' string"""
data = {}
for item in auth_response.split(','):
part = item.find("=")
if part>0:
data[item[:part].strip()] = item[part+1:].strip("\"")
return data
def getDigestResponse(data):
"""Creates the hash values that are returned"""
#first section could probably be stored in a data base
user = data.get("Digest username")
realm = data.get("realm")
valueA = md5()
valueA.update('%s:%s:%s' % (user, realm, 'secret'))
hashA = valueA.hexdigest()
#this section will change on request
nonce = data.get("nonce")
uri = data.get("uri")
method = data.get('method')
valueB = md5()
valueB.update("%s:%s"%(method,uri))
hashB = valueB.hexdigest()
value = md5()
value.update("%s:%s:%s"%(hashA,nonce,hashB))
return data.get("response")==value.hexdigest()
def digestAuthenticationFailed(environ,start_response):
"""Failed digest request"""
status = '401 Unauthorized'
response_headers = [('WWW-Authenticate','Digest realm="Secure Area" nonce="two"'),('Content-type','text/html')]
start_response(status,response_headers)
return ["<html><body>Authorization has failed</body></html>"]
def my_digest_app(environ, start_response):
"""Success"""
status = '200 OK'
response_headers = [('Content-type','text/html')]
start_response(status, response_headers)
return ['<html><body><p>Yo Yo, digest stylie.</p></body></html>']
"""
Creates a cherrypy wsgi server with three different locations, / ... no authentication
/basic... basic authentication
/digest ... digest authentication
"""
d = cwsgi.WSGIPathInfoDispatcher({'/': my_crazy_app, '/basic': authenticate_basic_app, '/digest':authenticate_digest_app})
server = cwsgi.CherryPyWSGIServer(('0.0.0.0', 8080), d)
if __name__ == '__main__':
try:
server.start()
except KeyboardInterrupt:
server.stop()
I got the http info from wikapedia, here
and I found some other info that I might add when I find it again.
Comments
create comment?