1 #!/usr/bin/env python 2 3 "Login redirection." 4 5 import md5 6 7 class LoginRedirectResource: 8 9 "A resource redirecting to a login URL." 10 11 def __init__(self, login_url, app_url, resource, authenticator, anonymous_parameter_name=None): 12 13 """ 14 Initialise the resource with a 'login_url', an 'app_url' where the 'resource' for 15 the application being protected should be reachable, and an 'authenticator'. 16 17 If the optional 'anonymous_parameter_name' is set, clients providing a parameter 18 of that name in the URL will not be authenticated, but then such clients will not 19 get a user identity associated with them. 20 """ 21 22 self.login_url = login_url 23 self.app_url = app_url 24 self.resource = resource 25 self.authenticator = authenticator 26 self.anonymous_parameter_name = anonymous_parameter_name 27 28 def respond(self, trans): 29 30 # Check for the anonymous parameter, if appropriate. 31 32 fields = trans.get_fields_from_path() 33 if self.anonymous_parameter_name is not None and fields.has_key(self.anonymous_parameter_name): 34 is_anonymous = 1 35 else: 36 is_anonymous = 0 37 38 # Check the authentication details with the specified authenticator. 39 40 if is_anonymous or self.authenticator.authenticate(trans): 41 self.resource.respond(trans) 42 else: 43 # Redirect to the login URL. 44 45 trans.set_header_value("Location", "%s?redirect=%s%s" % (self.login_url, self.app_url, self._encode(trans.get_path()))) 46 trans.set_response_code(307) 47 48 def _encode(self, url): 49 50 "Encode the given 'url' for redirection purposes." 51 52 return url.replace("?", "%3f").replace("&", "%26") 53 54 class LoginRedirectAuthenticator: 55 56 """ 57 An authenticator which verifies the credentials provided in a special login cookie. 58 """ 59 60 def __init__(self, secret_key, cookie_name=None): 61 62 "Initialise the authenticator with a 'secret_key' and an optional 'cookie_name'." 63 64 self.secret_key = secret_key 65 self.cookie_name = cookie_name or "LoginAuthenticator" 66 67 def authenticate(self, trans): 68 69 "Authenticate the originator of 'trans', updating the object if successful." 70 71 cookie = trans.get_cookie(self.cookie_name) 72 if cookie is None or cookie.value is None: 73 return 0 74 75 # Test the token from the cookie against a recreated token using the 76 # given information. 77 # NOTE: This should be moved into a common library. 78 79 username, code = cookie.value.split(":") 80 if code == md5.md5(username + self.secret_key).hexdigest(): 81 82 # Update the transaction with the user details. 83 84 trans.set_user(username) 85 return 1 86 else: 87 return 0 88 89 # vim: tabstop=4 expandtab shiftwidth=4