1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/WebStack/Resources/LoginRedirect.py Sun May 30 17:21:51 2004 +0000
1.3 @@ -0,0 +1,175 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"Login redirection."
1.7 +
1.8 +from WebStack.Helpers.Auth import get_token
1.9 +import WebStack.Generic
1.10 +
1.11 +class LoginRedirectResource:
1.12 +
1.13 + "A resource redirecting to a login URL."
1.14 +
1.15 + def __init__(self, login_url, app_url, resource, authenticator, anonymous_parameter_name=None,
1.16 + anonymous_username="anonymous", logout_parameter_name=None, logout_url="/",
1.17 + use_logout_redirect=1):
1.18 +
1.19 + """
1.20 + Initialise the resource with a 'login_url', an 'app_url' where the 'resource' for
1.21 + the application being protected should be reachable, and an 'authenticator'.
1.22 +
1.23 + If the optional 'anonymous_parameter_name' is set, clients providing a parameter
1.24 + of that name in the URL will not be authenticated, but then such clients will get
1.25 + a predefined user identity associated with them, configurable using the optional
1.26 + 'anonymous_username'.
1.27 +
1.28 + If the optional 'logout_parameter_name' is set, clients providing a parameter of
1.29 + that name in the URL will become logged out. After logging out, clients are
1.30 + redirected to a location which can be configured by the optional 'logout_url'.
1.31 +
1.32 + If the optional 'use_logout_redirect' flag is set to 0, a confirmation screen is
1.33 + given instead of redirecting the user to the 'logout_url'.
1.34 + """
1.35 +
1.36 + self.login_url = login_url
1.37 + self.app_url = app_url
1.38 + self.resource = resource
1.39 + self.authenticator = authenticator
1.40 + self.anonymous_parameter_name = anonymous_parameter_name
1.41 + self.anonymous_username = anonymous_username
1.42 + self.logout_parameter_name = logout_parameter_name
1.43 + self.logout_url = logout_url
1.44 + self.use_logout_redirect = use_logout_redirect
1.45 +
1.46 + def respond(self, trans):
1.47 +
1.48 + "Respond using the given transaction 'trans'."
1.49 +
1.50 + fields_path = trans.get_fields_from_path()
1.51 +
1.52 + # Check for the logout parameter, if appropriate.
1.53 +
1.54 + if self.logout_parameter_name is not None and fields_path.has_key(self.logout_parameter_name):
1.55 +
1.56 + # Remove the special cookie token, then pass on the transaction.
1.57 +
1.58 + self.authenticator.unset_token(trans)
1.59 +
1.60 + # Redirect to the logout URL.
1.61 +
1.62 + if self.use_logout_redirect:
1.63 + trans.set_header_value("Location", self.logout_url)
1.64 + trans.set_response_code(307)
1.65 +
1.66 + # Show the logout confirmation anyway.
1.67 +
1.68 + self._show_logout(trans, self.logout_url)
1.69 +
1.70 + # Check the authentication details with the specified authenticator.
1.71 +
1.72 + elif self.authenticator.authenticate(trans):
1.73 +
1.74 + # If successful, pass on the transaction.
1.75 +
1.76 + self.resource.respond(trans)
1.77 +
1.78 + # Check for the anonymous parameter, if appropriate.
1.79 +
1.80 + elif self.anonymous_parameter_name is not None and fields_path.has_key(self.anonymous_parameter_name):
1.81 +
1.82 + # Make a special cookie token, then pass on the transaction.
1.83 +
1.84 + self.authenticator.set_token(trans, self.anonymous_username)
1.85 + self.resource.respond(trans)
1.86 +
1.87 + else:
1.88 +
1.89 + # Redirect to the login URL.
1.90 +
1.91 + trans.set_header_value("Location", "%s?redirect=%s%s" % (
1.92 + self.login_url, self.app_url, self._encode(trans.get_path()))
1.93 + )
1.94 + trans.set_response_code(307)
1.95 +
1.96 + def _encode(self, url):
1.97 +
1.98 + "Encode the given 'url' for redirection purposes."
1.99 +
1.100 + return url.replace("?", "%3f").replace("&", "%26")
1.101 +
1.102 + def _show_logout(self, trans, redirect):
1.103 +
1.104 + """
1.105 + Write a confirmation page to 'trans' containing the 'redirect' URL which the
1.106 + client should be sent to upon logout.
1.107 + """
1.108 +
1.109 + # When logout takes place, show the login screen.
1.110 +
1.111 + trans.set_content_type(WebStack.Generic.ContentType("text/html"))
1.112 + out = trans.get_response_stream()
1.113 + out.write("""
1.114 +<html>
1.115 + <head>
1.116 + <title>Logout</title>
1.117 + </head>
1.118 + <body>
1.119 + <h1>Logout Successful</h1>
1.120 + <p>Please proceed <a href="%s">to the application</a>.</p>
1.121 + </body>
1.122 +</html>
1.123 +""" % redirect)
1.124 +
1.125 +class LoginRedirectAuthenticator:
1.126 +
1.127 + """
1.128 + An authenticator which verifies the credentials provided in a special login cookie.
1.129 + """
1.130 +
1.131 + def __init__(self, secret_key, cookie_name=None):
1.132 +
1.133 + "Initialise the authenticator with a 'secret_key' and an optional 'cookie_name'."
1.134 +
1.135 + self.secret_key = secret_key
1.136 + self.cookie_name = cookie_name or "LoginAuthenticator"
1.137 +
1.138 + def authenticate(self, trans):
1.139 +
1.140 + "Authenticate the originator of 'trans', updating the object if successful."
1.141 +
1.142 + cookie = trans.get_cookie(self.cookie_name)
1.143 + if cookie is None or cookie.value is None:
1.144 + return 0
1.145 +
1.146 + # Test the token from the cookie against a recreated token using the
1.147 + # given information.
1.148 +
1.149 + username, code = cookie.value.split(":")
1.150 + if cookie.value == get_token(username, self.secret_key):
1.151 +
1.152 + # Update the transaction with the user details.
1.153 +
1.154 + trans.set_user(username)
1.155 + return 1
1.156 + else:
1.157 + return 0
1.158 +
1.159 + def set_token(self, trans, username):
1.160 +
1.161 + "Set an authentication token in 'trans' with the given 'username'."
1.162 +
1.163 + trans.set_cookie_value(
1.164 + self.cookie_name,
1.165 + get_token(username, self.secret_key)
1.166 + )
1.167 +
1.168 + # Update the transaction with the user details.
1.169 +
1.170 + trans.set_user(username)
1.171 +
1.172 + def unset_token(self, trans):
1.173 +
1.174 + "Unset the authentication token in 'trans'."
1.175 +
1.176 + trans.delete_cookie(self.cookie_name)
1.177 +
1.178 +# vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/examples/BaseHTTPRequestHandler/SimpleWithLoginApp.py Sun May 30 16:41:22 2004 +0000
3.2 +++ b/examples/BaseHTTPRequestHandler/SimpleWithLoginApp.py Sun May 30 17:21:51 2004 +0000
3.3 @@ -1,8 +1,8 @@
3.4 #!/usr/bin/env python
3.5
3.6 from WebStack.Adapters import BaseHTTPRequestHandler
3.7 +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
3.8 from Simple import SimpleResource
3.9 -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
3.10 import BaseHTTPServer
3.11
3.12 # Special magic incantation.
4.1 --- a/examples/CGI/SimpleWithLoginHandler.py Sun May 30 16:41:22 2004 +0000
4.2 +++ b/examples/CGI/SimpleWithLoginHandler.py Sun May 30 17:21:51 2004 +0000
4.3 @@ -7,8 +7,8 @@
4.4 sys.path.append("/home/paulb/Software/Python/WebStack/examples/Common")
4.5
4.6 from WebStack.Adapters import CGI
4.7 +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
4.8 from Simple import SimpleResource
4.9 -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
4.10
4.11 resource = LoginRedirectResource(
4.12 login_url="http://localhost/cgi/login",
5.1 --- a/examples/Common/LoginRedirect/__init__.py Sun May 30 16:41:22 2004 +0000
5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
5.3 @@ -1,168 +0,0 @@
5.4 -#!/usr/bin/env python
5.5 -
5.6 -"Login redirection."
5.7 -
5.8 -from WebStack.Helpers.Auth import get_token
5.9 -import WebStack.Generic
5.10 -
5.11 -class LoginRedirectResource:
5.12 -
5.13 - "A resource redirecting to a login URL."
5.14 -
5.15 - def __init__(self, login_url, app_url, resource, authenticator, anonymous_parameter_name=None,
5.16 - anonymous_username="anonymous", logout_parameter_name=None, logout_url="/",
5.17 - use_logout_redirect=1):
5.18 -
5.19 - """
5.20 - Initialise the resource with a 'login_url', an 'app_url' where the 'resource' for
5.21 - the application being protected should be reachable, and an 'authenticator'.
5.22 -
5.23 - If the optional 'anonymous_parameter_name' is set, clients providing a parameter
5.24 - of that name in the URL will not be authenticated, but then such clients will get
5.25 - a predefined user identity associated with them, configurable using the optional
5.26 - 'anonymous_username'.
5.27 -
5.28 - If the optional 'logout_parameter_name' is set, clients providing a parameter of
5.29 - that name in the URL will become logged out. After logging out, clients are
5.30 - redirected to a location which can be configured by the optional 'logout_url'.
5.31 -
5.32 - If the optional 'use_logout_redirect' flag is set to 0, a confirmation screen is
5.33 - given instead of redirecting the user to the 'logout_url'.
5.34 - """
5.35 -
5.36 - self.login_url = login_url
5.37 - self.app_url = app_url
5.38 - self.resource = resource
5.39 - self.authenticator = authenticator
5.40 - self.anonymous_parameter_name = anonymous_parameter_name
5.41 - self.anonymous_username = anonymous_username
5.42 - self.logout_parameter_name = logout_parameter_name
5.43 - self.logout_url = logout_url
5.44 - self.use_logout_redirect = use_logout_redirect
5.45 -
5.46 - def respond(self, trans):
5.47 -
5.48 - fields_path = trans.get_fields_from_path()
5.49 -
5.50 - # Check for the logout parameter, if appropriate.
5.51 -
5.52 - if self.logout_parameter_name is not None and fields_path.has_key(self.logout_parameter_name):
5.53 -
5.54 - # Remove the special cookie token, then pass on the transaction.
5.55 -
5.56 - self.authenticator.unset_token(trans)
5.57 -
5.58 - # Redirect to the logout URL.
5.59 -
5.60 - if self.use_logout_redirect:
5.61 - trans.set_header_value("Location", self.logout_url)
5.62 - trans.set_response_code(307)
5.63 -
5.64 - # Show the logout confirmation anyway.
5.65 -
5.66 - self._show_logout(trans, self.logout_url)
5.67 -
5.68 - # Check the authentication details with the specified authenticator.
5.69 -
5.70 - elif self.authenticator.authenticate(trans):
5.71 -
5.72 - # If successful, pass on the transaction.
5.73 -
5.74 - self.resource.respond(trans)
5.75 -
5.76 - # Check for the anonymous parameter, if appropriate.
5.77 -
5.78 - elif self.anonymous_parameter_name is not None and fields_path.has_key(self.anonymous_parameter_name):
5.79 -
5.80 - # Make a special cookie token, then pass on the transaction.
5.81 -
5.82 - self.authenticator.set_token(trans, self.anonymous_username)
5.83 - self.resource.respond(trans)
5.84 -
5.85 - else:
5.86 -
5.87 - # Redirect to the login URL.
5.88 -
5.89 - trans.set_header_value("Location", "%s?redirect=%s%s" % (
5.90 - self.login_url, self.app_url, self._encode(trans.get_path()))
5.91 - )
5.92 - trans.set_response_code(307)
5.93 -
5.94 - def _encode(self, url):
5.95 -
5.96 - "Encode the given 'url' for redirection purposes."
5.97 -
5.98 - return url.replace("?", "%3f").replace("&", "%26")
5.99 -
5.100 - def _show_logout(self, trans, redirect):
5.101 -
5.102 - # When logout takes place, show the login screen.
5.103 -
5.104 - trans.set_content_type(WebStack.Generic.ContentType("text/html"))
5.105 - out = trans.get_response_stream()
5.106 - out.write("""
5.107 -<html>
5.108 - <head>
5.109 - <title>Logout</title>
5.110 - </head>
5.111 - <body>
5.112 - <h1>Logout Successful</h1>
5.113 - <p>Please proceed <a href="%s">to the application</a>.</p>
5.114 - </body>
5.115 -</html>
5.116 -""" % redirect)
5.117 -
5.118 -class LoginRedirectAuthenticator:
5.119 -
5.120 - """
5.121 - An authenticator which verifies the credentials provided in a special login cookie.
5.122 - """
5.123 -
5.124 - def __init__(self, secret_key, cookie_name=None):
5.125 -
5.126 - "Initialise the authenticator with a 'secret_key' and an optional 'cookie_name'."
5.127 -
5.128 - self.secret_key = secret_key
5.129 - self.cookie_name = cookie_name or "LoginAuthenticator"
5.130 -
5.131 - def authenticate(self, trans):
5.132 -
5.133 - "Authenticate the originator of 'trans', updating the object if successful."
5.134 -
5.135 - cookie = trans.get_cookie(self.cookie_name)
5.136 - if cookie is None or cookie.value is None:
5.137 - return 0
5.138 -
5.139 - # Test the token from the cookie against a recreated token using the
5.140 - # given information.
5.141 -
5.142 - username, code = cookie.value.split(":")
5.143 - if cookie.value == get_token(username, self.secret_key):
5.144 -
5.145 - # Update the transaction with the user details.
5.146 -
5.147 - trans.set_user(username)
5.148 - return 1
5.149 - else:
5.150 - return 0
5.151 -
5.152 - def set_token(self, trans, username):
5.153 -
5.154 - "Set an authentication token in 'trans' with the given 'username'."
5.155 -
5.156 - trans.set_cookie_value(
5.157 - self.cookie_name,
5.158 - get_token(username, self.secret_key)
5.159 - )
5.160 -
5.161 - # Update the transaction with the user details.
5.162 -
5.163 - trans.set_user(username)
5.164 -
5.165 - def unset_token(self, trans):
5.166 -
5.167 - "Unset the authentication token in 'trans'."
5.168 -
5.169 - trans.delete_cookie(self.cookie_name)
5.170 -
5.171 -# vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/examples/ModPython/SimpleWithLoginApp/SimpleWithLoginHandler.py Sun May 30 16:41:22 2004 +0000
6.2 +++ b/examples/ModPython/SimpleWithLoginApp/SimpleWithLoginHandler.py Sun May 30 17:21:51 2004 +0000
6.3 @@ -7,8 +7,8 @@
6.4 sys.path.append("/home/paulb/Software/Python/WebStack/examples/Common")
6.5
6.6 from WebStack.Adapters import ModPython
6.7 +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
6.8 from Simple import SimpleResource
6.9 -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
6.10
6.11 # NOTE: Not sure if the resource should be maintained in a resource pool.
6.12
7.1 --- a/examples/Twisted/SimpleWithLoginApp.py Sun May 30 16:41:22 2004 +0000
7.2 +++ b/examples/Twisted/SimpleWithLoginApp.py Sun May 30 17:21:51 2004 +0000
7.3 @@ -1,8 +1,8 @@
7.4 #!/usr/bin/env python
7.5
7.6 from WebStack.Adapters import Twisted
7.7 +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
7.8 from Simple import SimpleResource
7.9 -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
7.10 import twisted.web.server
7.11 import twisted.internet.reactor
7.12
8.1 --- a/examples/Webware/SimpleWithLoginApp/__init__.py Sun May 30 16:41:22 2004 +0000
8.2 +++ b/examples/Webware/SimpleWithLoginApp/__init__.py Sun May 30 17:21:51 2004 +0000
8.3 @@ -7,8 +7,8 @@
8.4 __version__ = "0.1"
8.5
8.6 from WebStack.Adapters.Webware import WebStackServletFactory
8.7 +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
8.8 from Simple import SimpleResource
8.9 -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
8.10
8.11 # NOTE: Initialising a shared resource.
8.12
9.1 --- a/examples/Webware/SimpleWithLoginContext/__init__.py Sun May 30 16:41:22 2004 +0000
9.2 +++ b/examples/Webware/SimpleWithLoginContext/__init__.py Sun May 30 17:21:51 2004 +0000
9.3 @@ -5,8 +5,8 @@
9.4 """
9.5
9.6 from WebStack.Adapters.Webware import WebStackURLParser
9.7 +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
9.8 from Simple import SimpleResource
9.9 -from LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
9.10
9.11 # NOTE: Initialising a shared resource.
9.12