# HG changeset patch # User paulb # Date 1085937711 0 # Node ID f2878dc56e5dd0919a9d9788a1fb6948eab92465 # Parent e621441ea8b8a60cfb7fca34808ccebecbdf54cb [project @ 2004-05-30 17:21:41 by paulb] Moved LoginRedirect from the examples to WebStack.Resources. diff -r e621441ea8b8 -r f2878dc56e5d WebStack/Resources/LoginRedirect.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebStack/Resources/LoginRedirect.py Sun May 30 17:21:51 2004 +0000 @@ -0,0 +1,175 @@ +#!/usr/bin/env python + +"Login redirection." + +from WebStack.Helpers.Auth import get_token +import WebStack.Generic + +class LoginRedirectResource: + + "A resource redirecting to a login URL." + + def __init__(self, login_url, app_url, resource, authenticator, anonymous_parameter_name=None, + anonymous_username="anonymous", logout_parameter_name=None, logout_url="/", + use_logout_redirect=1): + + """ + Initialise the resource with a 'login_url', an 'app_url' where the 'resource' for + the application being protected should be reachable, and an 'authenticator'. + + If the optional 'anonymous_parameter_name' is set, clients providing a parameter + of that name in the URL will not be authenticated, but then such clients will get + a predefined user identity associated with them, configurable using the optional + 'anonymous_username'. + + If the optional 'logout_parameter_name' is set, clients providing a parameter of + that name in the URL will become logged out. After logging out, clients are + redirected to a location which can be configured by the optional 'logout_url'. + + If the optional 'use_logout_redirect' flag is set to 0, a confirmation screen is + given instead of redirecting the user to the 'logout_url'. + """ + + self.login_url = login_url + self.app_url = app_url + self.resource = resource + self.authenticator = authenticator + self.anonymous_parameter_name = anonymous_parameter_name + self.anonymous_username = anonymous_username + self.logout_parameter_name = logout_parameter_name + self.logout_url = logout_url + self.use_logout_redirect = use_logout_redirect + + def respond(self, trans): + + "Respond using the given transaction 'trans'." + + fields_path = trans.get_fields_from_path() + + # Check for the logout parameter, if appropriate. + + if self.logout_parameter_name is not None and fields_path.has_key(self.logout_parameter_name): + + # Remove the special cookie token, then pass on the transaction. + + self.authenticator.unset_token(trans) + + # Redirect to the logout URL. + + if self.use_logout_redirect: + trans.set_header_value("Location", self.logout_url) + trans.set_response_code(307) + + # Show the logout confirmation anyway. + + self._show_logout(trans, self.logout_url) + + # Check the authentication details with the specified authenticator. + + elif self.authenticator.authenticate(trans): + + # If successful, pass on the transaction. + + self.resource.respond(trans) + + # Check for the anonymous parameter, if appropriate. + + elif self.anonymous_parameter_name is not None and fields_path.has_key(self.anonymous_parameter_name): + + # Make a special cookie token, then pass on the transaction. + + self.authenticator.set_token(trans, self.anonymous_username) + self.resource.respond(trans) + + else: + + # Redirect to the login URL. + + trans.set_header_value("Location", "%s?redirect=%s%s" % ( + self.login_url, self.app_url, self._encode(trans.get_path())) + ) + trans.set_response_code(307) + + def _encode(self, url): + + "Encode the given 'url' for redirection purposes." + + return url.replace("?", "%3f").replace("&", "%26") + + def _show_logout(self, trans, redirect): + + """ + Write a confirmation page to 'trans' containing the 'redirect' URL which the + client should be sent to upon logout. + """ + + # When logout takes place, show the login screen. + + trans.set_content_type(WebStack.Generic.ContentType("text/html")) + out = trans.get_response_stream() + out.write(""" + + + Logout + + +

Logout Successful

+

Please proceed to the application.

+ + +""" % redirect) + +class LoginRedirectAuthenticator: + + """ + An authenticator which verifies the credentials provided in a special login cookie. + """ + + def __init__(self, secret_key, cookie_name=None): + + "Initialise the authenticator with a 'secret_key' and an optional 'cookie_name'." + + self.secret_key = secret_key + self.cookie_name = cookie_name or "LoginAuthenticator" + + def authenticate(self, trans): + + "Authenticate the originator of 'trans', updating the object if successful." + + cookie = trans.get_cookie(self.cookie_name) + if cookie is None or cookie.value is None: + return 0 + + # Test the token from the cookie against a recreated token using the + # given information. + + username, code = cookie.value.split(":") + if cookie.value == get_token(username, self.secret_key): + + # Update the transaction with the user details. + + trans.set_user(username) + return 1 + else: + return 0 + + def set_token(self, trans, username): + + "Set an authentication token in 'trans' with the given 'username'." + + trans.set_cookie_value( + self.cookie_name, + get_token(username, self.secret_key) + ) + + # Update the transaction with the user details. + + trans.set_user(username) + + def unset_token(self, trans): + + "Unset the authentication token in 'trans'." + + trans.delete_cookie(self.cookie_name) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r e621441ea8b8 -r f2878dc56e5d WebStack/Resources/__init__.py diff -r e621441ea8b8 -r f2878dc56e5d examples/BaseHTTPRequestHandler/SimpleWithLoginApp.py --- a/examples/BaseHTTPRequestHandler/SimpleWithLoginApp.py Sun May 30 16:41:22 2004 +0000 +++ b/examples/BaseHTTPRequestHandler/SimpleWithLoginApp.py Sun May 30 17:21:51 2004 +0000 @@ -1,8 +1,8 @@ #!/usr/bin/env python from WebStack.Adapters import BaseHTTPRequestHandler +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator from Simple import SimpleResource -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator import BaseHTTPServer # Special magic incantation. diff -r e621441ea8b8 -r f2878dc56e5d examples/CGI/SimpleWithLoginHandler.py --- a/examples/CGI/SimpleWithLoginHandler.py Sun May 30 16:41:22 2004 +0000 +++ b/examples/CGI/SimpleWithLoginHandler.py Sun May 30 17:21:51 2004 +0000 @@ -7,8 +7,8 @@ sys.path.append("/home/paulb/Software/Python/WebStack/examples/Common") from WebStack.Adapters import CGI +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator from Simple import SimpleResource -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator resource = LoginRedirectResource( login_url="http://localhost/cgi/login", diff -r e621441ea8b8 -r f2878dc56e5d examples/Common/LoginRedirect/__init__.py --- a/examples/Common/LoginRedirect/__init__.py Sun May 30 16:41:22 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -#!/usr/bin/env python - -"Login redirection." - -from WebStack.Helpers.Auth import get_token -import WebStack.Generic - -class LoginRedirectResource: - - "A resource redirecting to a login URL." - - def __init__(self, login_url, app_url, resource, authenticator, anonymous_parameter_name=None, - anonymous_username="anonymous", logout_parameter_name=None, logout_url="/", - use_logout_redirect=1): - - """ - Initialise the resource with a 'login_url', an 'app_url' where the 'resource' for - the application being protected should be reachable, and an 'authenticator'. - - If the optional 'anonymous_parameter_name' is set, clients providing a parameter - of that name in the URL will not be authenticated, but then such clients will get - a predefined user identity associated with them, configurable using the optional - 'anonymous_username'. - - If the optional 'logout_parameter_name' is set, clients providing a parameter of - that name in the URL will become logged out. After logging out, clients are - redirected to a location which can be configured by the optional 'logout_url'. - - If the optional 'use_logout_redirect' flag is set to 0, a confirmation screen is - given instead of redirecting the user to the 'logout_url'. - """ - - self.login_url = login_url - self.app_url = app_url - self.resource = resource - self.authenticator = authenticator - self.anonymous_parameter_name = anonymous_parameter_name - self.anonymous_username = anonymous_username - self.logout_parameter_name = logout_parameter_name - self.logout_url = logout_url - self.use_logout_redirect = use_logout_redirect - - def respond(self, trans): - - fields_path = trans.get_fields_from_path() - - # Check for the logout parameter, if appropriate. - - if self.logout_parameter_name is not None and fields_path.has_key(self.logout_parameter_name): - - # Remove the special cookie token, then pass on the transaction. - - self.authenticator.unset_token(trans) - - # Redirect to the logout URL. - - if self.use_logout_redirect: - trans.set_header_value("Location", self.logout_url) - trans.set_response_code(307) - - # Show the logout confirmation anyway. - - self._show_logout(trans, self.logout_url) - - # Check the authentication details with the specified authenticator. - - elif self.authenticator.authenticate(trans): - - # If successful, pass on the transaction. - - self.resource.respond(trans) - - # Check for the anonymous parameter, if appropriate. - - elif self.anonymous_parameter_name is not None and fields_path.has_key(self.anonymous_parameter_name): - - # Make a special cookie token, then pass on the transaction. - - self.authenticator.set_token(trans, self.anonymous_username) - self.resource.respond(trans) - - else: - - # Redirect to the login URL. - - trans.set_header_value("Location", "%s?redirect=%s%s" % ( - self.login_url, self.app_url, self._encode(trans.get_path())) - ) - trans.set_response_code(307) - - def _encode(self, url): - - "Encode the given 'url' for redirection purposes." - - return url.replace("?", "%3f").replace("&", "%26") - - def _show_logout(self, trans, redirect): - - # When logout takes place, show the login screen. - - trans.set_content_type(WebStack.Generic.ContentType("text/html")) - out = trans.get_response_stream() - out.write(""" - - - Logout - - -

Logout Successful

-

Please proceed to the application.

- - -""" % redirect) - -class LoginRedirectAuthenticator: - - """ - An authenticator which verifies the credentials provided in a special login cookie. - """ - - def __init__(self, secret_key, cookie_name=None): - - "Initialise the authenticator with a 'secret_key' and an optional 'cookie_name'." - - self.secret_key = secret_key - self.cookie_name = cookie_name or "LoginAuthenticator" - - def authenticate(self, trans): - - "Authenticate the originator of 'trans', updating the object if successful." - - cookie = trans.get_cookie(self.cookie_name) - if cookie is None or cookie.value is None: - return 0 - - # Test the token from the cookie against a recreated token using the - # given information. - - username, code = cookie.value.split(":") - if cookie.value == get_token(username, self.secret_key): - - # Update the transaction with the user details. - - trans.set_user(username) - return 1 - else: - return 0 - - def set_token(self, trans, username): - - "Set an authentication token in 'trans' with the given 'username'." - - trans.set_cookie_value( - self.cookie_name, - get_token(username, self.secret_key) - ) - - # Update the transaction with the user details. - - trans.set_user(username) - - def unset_token(self, trans): - - "Unset the authentication token in 'trans'." - - trans.delete_cookie(self.cookie_name) - -# vim: tabstop=4 expandtab shiftwidth=4 diff -r e621441ea8b8 -r f2878dc56e5d examples/ModPython/SimpleWithLoginApp/SimpleWithLoginHandler.py --- a/examples/ModPython/SimpleWithLoginApp/SimpleWithLoginHandler.py Sun May 30 16:41:22 2004 +0000 +++ b/examples/ModPython/SimpleWithLoginApp/SimpleWithLoginHandler.py Sun May 30 17:21:51 2004 +0000 @@ -7,8 +7,8 @@ sys.path.append("/home/paulb/Software/Python/WebStack/examples/Common") from WebStack.Adapters import ModPython +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator from Simple import SimpleResource -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator # NOTE: Not sure if the resource should be maintained in a resource pool. diff -r e621441ea8b8 -r f2878dc56e5d examples/Twisted/SimpleWithLoginApp.py --- a/examples/Twisted/SimpleWithLoginApp.py Sun May 30 16:41:22 2004 +0000 +++ b/examples/Twisted/SimpleWithLoginApp.py Sun May 30 17:21:51 2004 +0000 @@ -1,8 +1,8 @@ #!/usr/bin/env python from WebStack.Adapters import Twisted +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator from Simple import SimpleResource -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator import twisted.web.server import twisted.internet.reactor diff -r e621441ea8b8 -r f2878dc56e5d examples/Webware/SimpleWithLoginApp/__init__.py --- a/examples/Webware/SimpleWithLoginApp/__init__.py Sun May 30 16:41:22 2004 +0000 +++ b/examples/Webware/SimpleWithLoginApp/__init__.py Sun May 30 17:21:51 2004 +0000 @@ -7,8 +7,8 @@ __version__ = "0.1" from WebStack.Adapters.Webware import WebStackServletFactory +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator from Simple import SimpleResource -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator # NOTE: Initialising a shared resource. diff -r e621441ea8b8 -r f2878dc56e5d examples/Webware/SimpleWithLoginContext/__init__.py --- a/examples/Webware/SimpleWithLoginContext/__init__.py Sun May 30 16:41:22 2004 +0000 +++ b/examples/Webware/SimpleWithLoginContext/__init__.py Sun May 30 17:21:51 2004 +0000 @@ -5,8 +5,8 @@ """ from WebStack.Adapters.Webware import WebStackURLParser +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator from Simple import SimpleResource -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator # NOTE: Initialising a shared resource.