# HG changeset patch # User paulb # Date 1124994109 0 # Node ID 8ebbbe08120e2dda2e3be337642f40cbb7b8008c # Parent 80fb0aaf134b2f86161f7f0136b391f48142b1ca [project @ 2005-08-25 18:21:45 by paulb] Updated the Login and LoginRedirect resources to use the updated path API. diff -r 80fb0aaf134b -r 8ebbbe08120e README.txt --- a/README.txt Thu Aug 25 18:20:19 2005 +0000 +++ b/README.txt Thu Aug 25 18:21:49 2005 +0000 @@ -59,6 +59,8 @@ get_virtual_path_info, get_processed_virtual_path_info and get_fields_from_path to return Unicode data decoded using the optional encoding parameter or a common default encoding. +Updated/fixed LoginResource and LoginRedirectResource to use the updated path +API and to handle special characters properly. Added convenience methods to Transaction for the decoding and encoding of path values (to and from Unicode objects) - see the decode_path and encode_path methods. diff -r 80fb0aaf134b -r 8ebbbe08120e WebStack/Resources/Login.py --- a/WebStack/Resources/Login.py Thu Aug 25 18:20:19 2005 +0000 +++ b/WebStack/Resources/Login.py Thu Aug 25 18:21:49 2005 +0000 @@ -28,67 +28,95 @@ "A resource providing a login screen." - def __init__(self, authenticator, use_redirect=1): + encoding = "utf-8" + + def __init__(self, authenticator, use_redirect=1, urlencoding=None): """ Initialise the resource with an 'authenticator'. - If the optional 'use_redirect' flag is set to 0, a confirmation screen is given - instead of redirecting the user back to the original application. + If the optional 'use_redirect' flag is set to 0, a confirmation screen + is given instead of redirecting the user back to the original + application. + + The optional 'urlencoding' parameter allows a special encoding to be + used in producing the redirection path. """ self.authenticator = authenticator self.use_redirect = use_redirect + self.urlencoding = urlencoding def respond(self, trans): "Respond using the transaction 'trans'." - fields_path = trans.get_fields_from_path() - fields_body = trans.get_fields_from_body() + fields_path = trans.get_fields_from_path(self.urlencoding) + fields_body = trans.get_fields_from_body(self.encoding) # NOTE: Handle missing redirects better. - if fields_body.has_key("redirect"): - redirects = fields_body["redirect"] - redirect = redirects[0] - elif fields_path.has_key("redirect"): - redirects = fields_path["redirect"] - redirect = redirects[0] + if fields_body.has_key("app"): + apps = fields_body["app"] + app = apps[0] + elif fields_path.has_key("app"): + apps = fields_path["app"] + app = apps[0] else: - redirect = "" + app = u"" + + if fields_body.has_key("path"): + paths = fields_body["path"] + path = paths[0] + elif fields_path.has_key("path"): + paths = fields_path["path"] + path = paths[0] + else: + path = u"" + + if fields_body.has_key("qs"): + qss = fields_body["qs"] + qs = qss[0] + elif fields_path.has_key("qs"): + qss = fields_path["qs"] + qs = qss[0] + else: + qs = u"" # Check for a submitted login form. if fields_body.has_key("login"): if self.authenticator.authenticate(trans): - self._redirect(trans, redirect) + self._redirect(trans, app, path, qs) return # Otherwise, show the login form. - self._show_login(trans, redirect) + self._show_login(trans, app, path, qs) + + def _redirect(self, trans, app, path, qs): - def _redirect(self, trans, redirect): - - "Redirect the client using 'trans' and the given 'redirect' URL." + """ + Redirect the client using 'trans' and the given 'app', 'path' and 'qs' + details. + """ if self.use_redirect: - trans.set_header_value("Location", redirect) + trans.set_header_value("Location", app + trans.encode_path(path, self.urlencoding) + qs) trans.set_response_code(302) # was 307 # Show the success page anyway. - self._show_success(trans, redirect) + self._show_success(trans, app, path, qs) - def _show_login(self, trans, redirect): + def _show_login(self, trans, app, path, qs): """ Writes a login screen using the transaction 'trans', including details of the - 'redirect' URL which the client was attempting to access. + 'app', 'path' and 'qs' which the client was attempting to access. """ - trans.set_content_type(WebStack.Generic.ContentType("text/html")) + trans.set_content_type(WebStack.Generic.ContentType("text/html", self.encoding)) out = trans.get_response_stream() out.write(""" @@ -101,18 +129,20 @@

Username:

Password:

- + + + -""" % redirect) +""" % (app, path, qs)) - def _show_success(self, trans, redirect): + def _show_success(self, trans, app, path, qs): # When authentication fails or is yet to take place, show the login # screen. - trans.set_content_type(WebStack.Generic.ContentType("text/html")) + trans.set_content_type(WebStack.Generic.ContentType("text/html", self.encoding)) out = trans.get_response_stream() out.write(""" @@ -121,16 +151,10 @@

Login Successful

-

Please proceed to the application.

+

Please proceed to the application.

-""" % redirect) - - def _decode(self, url): - - "Decode the given 'url' for redirection purposes." - - return url.replace("%3f", "?").replace("%26", "&") +""" % (app, trans.encode_path(path, self.urlencoding), qs)) class LoginAuthenticator: diff -r 80fb0aaf134b -r 8ebbbe08120e WebStack/Resources/LoginRedirect.py --- a/WebStack/Resources/LoginRedirect.py Thu Aug 25 18:20:19 2005 +0000 +++ b/WebStack/Resources/LoginRedirect.py Thu Aug 25 18:21:49 2005 +0000 @@ -30,23 +30,28 @@ 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): + use_logout_redirect=1, urlencoding=None): """ - Initialise the resource with a 'login_url', an 'app_url' where the 'resource' for - the application being protected should be reachable, and an 'authenticator'. + 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 '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 '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'. - 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'. + The optional 'urlencoding' parameter allows a special encoding to be + used in producing the redirection path. """ self.login_url = login_url @@ -58,12 +63,13 @@ self.logout_parameter_name = logout_parameter_name self.logout_url = logout_url self.use_logout_redirect = use_logout_redirect + self.urlencoding = urlencoding def respond(self, trans): "Respond using the given transaction 'trans'." - fields_path = trans.get_fields_from_path() + fields_path = trans.get_fields_from_path(self.urlencoding) # Check for the logout parameter, if appropriate. @@ -104,17 +110,19 @@ # 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())) + path = trans.get_path_without_query(self.urlencoding) + qs = trans.get_query_string() + if qs: + qs = "?" + qs + + trans.set_header_value("Location", "%s?app=%s&path=%s&qs=%s" % ( + self.login_url, + trans.encode_path(self.app_url, self.urlencoding), + trans.encode_path(path, self.urlencoding), + trans.encode_path(qs, self.urlencoding)) ) trans.set_response_code(302) # was 307 - def _encode(self, url): - - "Encode the given 'url' for redirection purposes." - - return url.replace("?", "%3f").replace("&", "%26") - def _show_logout(self, trans, redirect): """