1 #!/usr/bin/env python 2 3 "Login redirection." 4 5 from WebStack.Helpers.Auth import get_token 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 anonymous_username="anonymous"): 13 14 """ 15 Initialise the resource with a 'login_url', an 'app_url' where the 'resource' for 16 the application being protected should be reachable, and an 'authenticator'. 17 18 If the optional 'anonymous_parameter_name' is set, clients providing a parameter 19 of that name in the URL will not be authenticated, but then such clients will get 20 a predefined user identity associated with them, configurable using the optional 21 'anonymous_username'. 22 """ 23 24 self.login_url = login_url 25 self.app_url = app_url 26 self.resource = resource 27 self.authenticator = authenticator 28 self.anonymous_parameter_name = anonymous_parameter_name 29 self.anonymous_username = anonymous_username 30 31 def respond(self, trans): 32 33 fields_path = trans.get_fields_from_path() 34 35 # Check the authentication details with the specified authenticator. 36 37 if self.authenticator.authenticate(trans): 38 39 # If successful, pass on the transaction. 40 41 self.resource.respond(trans) 42 43 # Check for the anonymous parameter, if appropriate. 44 45 elif self.anonymous_parameter_name is not None and fields_path.has_key(self.anonymous_parameter_name): 46 47 # Make a special cookie token, then pass on the transaction. 48 49 self.authenticator.set_token(trans, self.anonymous_username) 50 self.resource.respond(trans) 51 52 else: 53 54 # Redirect to the login URL. 55 56 trans.set_header_value("Location", "%s?redirect=%s%s" % ( 57 self.login_url, self.app_url, self._encode(trans.get_path())) 58 ) 59 trans.set_response_code(307) 60 61 def _encode(self, url): 62 63 "Encode the given 'url' for redirection purposes." 64 65 return url.replace("?", "%3f").replace("&", "%26") 66 67 class LoginRedirectAuthenticator: 68 69 """ 70 An authenticator which verifies the credentials provided in a special login cookie. 71 """ 72 73 def __init__(self, secret_key, cookie_name=None): 74 75 "Initialise the authenticator with a 'secret_key' and an optional 'cookie_name'." 76 77 self.secret_key = secret_key 78 self.cookie_name = cookie_name or "LoginAuthenticator" 79 80 def authenticate(self, trans): 81 82 "Authenticate the originator of 'trans', updating the object if successful." 83 84 cookie = trans.get_cookie(self.cookie_name) 85 if cookie is None or cookie.value is None: 86 return 0 87 88 # Test the token from the cookie against a recreated token using the 89 # given information. 90 91 username, code = cookie.value.split(":") 92 if cookie.value == get_token(username, self.secret_key): 93 94 # Update the transaction with the user details. 95 96 trans.set_user(username) 97 return 1 98 else: 99 return 0 100 101 def set_token(self, trans, username): 102 103 "Set an authentication in the 'trans' with the given 'username'." 104 105 trans.set_cookie_value( 106 self.cookie_name, 107 get_token(username, self.secret_key) 108 ) 109 110 # Update the transaction with the user details. 111 112 trans.set_user(username) 113 114 # vim: tabstop=4 expandtab shiftwidth=4