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