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