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 app = parameters.get("app", [""])[0] 107 108 # Either redirect or switch to the success template. 109 110 if self.use_redirect: 111 trans.redirect(app) 112 else: 113 template_name = "success" 114 doc = form.new_instance("success") 115 successelem = doc.xpath(self.path_to_success_element)[0] 116 successelem.setAttribute("location", app) 117 else: 118 error = doc.createElement("error") 119 logelem.appendChild(error) 120 error.setAttribute("message", "Username or password not valid") 121 122 # Start the response. 123 124 trans.set_content_type(ContentType("application/xhtml+xml")) 125 stylesheet_parameters = {} 126 references = {} 127 128 # Set up translations. 129 130 if self.document_resources.has_key("translations"): 131 translations_xml = self.prepare_document("translations") 132 133 try: 134 language = trans.get_content_languages()[0] 135 except IndexError: 136 language = "en" 137 138 stylesheet_parameters["locale"] = language 139 references["translations"] = translations_xml 140 141 # Complete the response. 142 143 trans_xsl = self.prepare_output(template_name) 144 stylesheet_parameters["root"] = attributes["root"] 145 self.send_output(trans, [trans_xsl], doc, stylesheet_parameters, references=references) 146 147 class LoginRedirectResource(WebStack.Resources.LoginRedirect.LoginRedirectResource): 148 149 "A redirect resource which uses dynamic knowledge about the URL space." 150 151 def __init__(self, host, path_to_login, *args, **kw): 152 153 """ 154 Initialise the resource with the 'host', 'path_to_login' (the path from 155 the root of the application to the login screen), and other 156 LoginRedirectResource details. 157 158 To get the root of the application, this resource needs an attribute on 159 the transaction called "root". 160 161 Examples of 'path_to_login' with "root" attribute and result: 162 163 "login", "/" -> "/login" 164 "login", "/app/" -> "/app/login" 165 "app/login", "/" -> "/app/login" 166 """ 167 168 self.host = host 169 self.path_to_login = path_to_login 170 WebStack.Resources.LoginRedirect.LoginRedirectResource.__init__(self, *args, **kw) 171 172 def get_app_url(self, trans): 173 return self.host 174 175 def get_login_url(self, trans): 176 return self.host + trans.get_attributes()["root"] + self.path_to_login 177 178 # vim: tabstop=4 expandtab shiftwidth=4