1 #!/usr/bin/env python 2 3 """ 4 Login resources for XSLForms applications. These resources use "root" attributes 5 on transaction objects, and therefore should be defined within the appropriate 6 resources in site maps. 7 8 Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk> 9 10 This program is free software; you can redistribute it and/or modify it under 11 the terms of the GNU Lesser General Public License as published by the Free 12 Software Foundation; either version 3 of the License, or (at your option) any 13 later version. 14 15 This program is distributed in the hope that it will be useful, but WITHOUT 16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 18 details. 19 20 You should have received a copy of the GNU Lesser General Public License along 21 with this program. If not, see <http://www.gnu.org/licenses/>. 22 """ 23 24 from WebStack.Generic import ContentType, EndOfResponse 25 import XSLForms.Resources.WebResources 26 27 import WebStack.Resources.LoginRedirect # LoginRedirectResource 28 29 class LoginResource(XSLForms.Resources.WebResources.XSLFormsResource): 30 31 """ 32 A login screen resource which should be modified or subclassed to define the 33 following attributes: 34 35 * resource_dir 36 * template_resources - including a "login" entry for the login screen and 37 a "success" entry for a screen indicating a 38 successful login (used when redirects are not in 39 use) 40 * document_resources - including a "translations" entry 41 42 The latter attribute is optional. 43 44 The login template must define a "login" action, and provide a document 45 structure where the login credentials can be found through this class's 46 'path_to_login_element' attribute (which can be overridden or modified). 47 Such a structure would be as follows for the default configuration: 48 49 <login username="..." password="..."/> 50 51 The success template must provide a document structure where the location of 52 the application can be found through this class's 'path_to_success_element' 53 attribute (which can be overridden or modified). Such a structure would be 54 as follows for the default configuration: 55 56 <success location="..."/> 57 """ 58 59 path_to_login_element = "/login" 60 path_to_success_element = "/success" 61 62 def __init__(self, authenticator, use_redirect=1): 63 64 """ 65 Initialise the resource with an 'authenticator'. If the optional 66 'use_redirect' parameter is specified and set to a false value (unlike 67 the default), 68 69 To get the root of the application, this resource needs an attribute on 70 the transaction called "root". 71 """ 72 73 self.authenticator = authenticator 74 self.use_redirect = use_redirect 75 76 def respond_to_form(self, trans, form): 77 78 """ 79 Respond to a request having the given transaction 'trans' and the given 80 'form' information. 81 """ 82 83 parameters = form.get_parameters() 84 documents = form.get_documents() 85 attributes = trans.get_attributes() 86 87 # Ensure the presence of a document. 88 89 if documents.has_key("login"): 90 doc = documents["login"] 91 else: 92 doc = form.new_instance("login") 93 94 template_name = "login" 95 96 # NOTE: Consider initialisation of both the login and success documents. 97 98 # Test for login. 99 100 if parameters.has_key("login"): 101 logelem = doc.xpath(self.path_to_login_element)[0] 102 username = logelem.getAttribute("username") 103 password = logelem.getAttribute("password") 104 105 if self.authenticator.authenticate(trans, username, password): 106 107 # Read the application's location from form parameters and any 108 # fields in the URL. 109 110 app = parameters.get("app", trans.get_fields_from_path().get("app", [""]))[0] 111 112 # Either redirect or switch to the success template. 113 114 if self.use_redirect: 115 trans.redirect(app) 116 else: 117 template_name = "success" 118 doc = form.new_instance("success") 119 successelem = doc.xpath(self.path_to_success_element)[0] 120 successelem.setAttribute("location", app) 121 else: 122 error = doc.createElement("error") 123 logelem.appendChild(error) 124 error.setAttribute("message", "Username or password not valid") 125 126 # Start the response. 127 128 trans.set_content_type(ContentType("application/xhtml+xml")) 129 stylesheet_parameters = {} 130 references = {} 131 132 # Set up translations. 133 134 if self.document_resources.has_key("translations"): 135 translations_xml = self.prepare_document("translations") 136 137 try: 138 language = trans.get_content_languages()[0] 139 except IndexError: 140 language = "en" 141 142 stylesheet_parameters["locale"] = language 143 references["translations"] = translations_xml 144 145 # Complete the response. 146 147 trans_xsl = self.prepare_output(template_name) 148 stylesheet_parameters["root"] = attributes["root"] 149 self.send_output(trans, [trans_xsl], doc, stylesheet_parameters, references=references) 150 151 class LoginRedirectResource(WebStack.Resources.LoginRedirect.LoginRedirectResource): 152 153 "A redirect resource which uses dynamic knowledge about the URL space." 154 155 def __init__(self, host, path_to_login, *args, **kw): 156 157 """ 158 Initialise the resource with the 'host', 'path_to_login' (the path from 159 the root of the application to the login screen), and other 160 LoginRedirectResource details. 161 162 To get the root of the application, this resource needs an attribute on 163 the transaction called "root". 164 165 Examples of 'path_to_login' with "root" attribute and result: 166 167 "login", "/" -> "/login" 168 "login", "/app/" -> "/app/login" 169 "app/login", "/" -> "/app/login" 170 """ 171 172 self.host = host 173 self.path_to_login = path_to_login 174 WebStack.Resources.LoginRedirect.LoginRedirectResource.__init__(self, *args, **kw) 175 176 def get_app_url(self, trans): 177 return self.host 178 179 def get_login_url(self, trans): 180 return self.host + trans.get_attributes()["root"] + self.path_to_login 181 182 # vim: tabstop=4 expandtab shiftwidth=4