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