1 #!/usr/bin/env python 2 3 "An example login screen." 4 5 import WebStack.Generic 6 import md5 7 8 class LoginResource: 9 10 "A resource providing a login screen." 11 12 def __init__(self, authenticator): 13 14 "Initialise the resource with an 'authenticator'." 15 16 self.authenticator = authenticator 17 18 def respond(self, trans): 19 20 fields = trans.get_fields_from_body() 21 redirect = "" 22 23 if fields.has_key("redirect"): 24 redirects = fields["redirect"] 25 redirect = redirects[0] 26 if self.authenticator.authenticate(trans): 27 trans.set_header_value("Location", redirect) 28 trans.set_response_code(307) 29 return 30 else: 31 fields = trans.get_fields_from_path() 32 if fields.has_key("redirect"): 33 redirects = fields["redirect"] 34 redirect = redirects[0] 35 36 # When authentication fails or is yet to take place, show the login 37 # screen. 38 39 trans.set_content_type(WebStack.Generic.ContentType("text/html")) 40 out = trans.get_response_stream() 41 out.write(""" 42 <html> 43 <head> 44 <title>Login Example</title> 45 </head> 46 <body> 47 <h1>Login</h1> 48 <form method="POST"> 49 <p>Username: <input name="username" type="text" size="12"/></p> 50 <p>Password: <input name="password" type="text" size="12"/></p> 51 <p><input name="login" type="submit" value="Login"/></p> 52 <input name="redirect" type="hidden" value="%s"/> 53 </form> 54 </body> 55 </html> 56 """ % redirect) 57 58 def _decode(self, url): 59 60 "Decode the given 'url' for redirection purposes." 61 62 return url.replace("%3f", "?").replace("%26", "&") 63 64 class LoginAuthenticator: 65 66 def __init__(self, secret_key, credentials, cookie_name=None): 67 68 """ 69 Initialise the authenticator with a 'secret_key', the authenticator's registry of 70 'credentials' and an optional 'cookie_name'. 71 72 The 'credentials' must be an object which supports tests of the form 73 '(username, password) in credentials'. 74 """ 75 76 self.secret_key = secret_key 77 self.credentials = credentials 78 self.cookie_name = cookie_name or "LoginAuthenticator" 79 80 def authenticate(self, trans): 81 82 # Process any supplied parameters. 83 84 fields = trans.get_fields_from_body() 85 86 if fields.has_key("username") and fields.has_key("password"): 87 usernames, passwords = fields["username"], fields["password"] 88 89 # Insist on only one username and password. 90 91 if len(usernames) == 1 and len(passwords) == 1: 92 username, password = usernames[0], passwords[0] 93 94 # Check against the class's credentials. 95 96 if (username, password) in self.credentials: 97 98 # Make a special cookie token. 99 # NOTE: This should be moved into a common library. 100 101 trans.set_cookie_value( 102 self.cookie_name, 103 username + ":" + md5.md5(username + self.secret_key).hexdigest() 104 ) 105 106 return 1 107 108 return 0 109 110 # vim: tabstop=4 expandtab shiftwidth=4