1.1 --- a/XSLForms/Resources/Login.py Mon Nov 19 00:16:57 2007 +0000
1.2 +++ b/XSLForms/Resources/Login.py Mon Nov 19 00:18:17 2007 +0000
1.3 @@ -25,7 +25,6 @@
1.4 import XSLForms.Resources.WebResources
1.5
1.6 import WebStack.Resources.LoginRedirect # LoginRedirectResource
1.7 -import WebStack.Resources.Login # get_target
1.8
1.9 class LoginResource(XSLForms.Resources.WebResources.XSLFormsResource):
1.10
1.11 @@ -104,17 +103,17 @@
1.12 password = logelem.getAttribute("password")
1.13
1.14 if self.authenticator.authenticate(trans, username, password):
1.15 - app, path, qs = WebStack.Resources.Login.get_target(trans)
1.16 + app = parameters.get("app", [""])[0]
1.17
1.18 # Either redirect or switch to the success template.
1.19
1.20 if self.use_redirect:
1.21 - trans.redirect(app + trans.encode_path(path) + qs)
1.22 + trans.redirect(app)
1.23 else:
1.24 template_name = "success"
1.25 doc = form.new_instance("success")
1.26 successelem = doc.xpath(self.path_to_success_element)[0]
1.27 - successelem.setAttribute("location", app + trans.encode_path(path) + qs)
1.28 + successelem.setAttribute("location", app)
1.29 else:
1.30 error = doc.createElement("error")
1.31 logelem.appendChild(error)
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/XSLForms/Resources/OpenIDLogin.py Mon Nov 19 00:18:17 2007 +0000
2.3 @@ -0,0 +1,219 @@
2.4 +#!/usr/bin/env python
2.5 +
2.6 +"""
2.7 +OpenID Login resources for XSLForms applications. These resources use "root"
2.8 +attributes on transaction objects, and therefore should be defined within the
2.9 +appropriate resources in site maps.
2.10 +
2.11 +Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
2.12 +
2.13 +This program is free software; you can redistribute it and/or modify it under
2.14 +the terms of the GNU Lesser General Public License as published by the Free
2.15 +Software Foundation; either version 3 of the License, or (at your option) any
2.16 +later version.
2.17 +
2.18 +This program is distributed in the hope that it will be useful, but WITHOUT
2.19 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2.20 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2.21 +details.
2.22 +
2.23 +You should have received a copy of the GNU Lesser General Public License along
2.24 +with this program. If not, see <http://www.gnu.org/licenses/>.
2.25 +"""
2.26 +
2.27 +from WebStack.Generic import ContentType, EndOfResponse
2.28 +from WebStack.Resources.OpenIDLogin import OpenIDLoginUtils
2.29 +from XSLForms.Resources.WebResources import XSLFormsResource
2.30 +
2.31 +import WebStack.Resources.OpenIDRedirect # LoginRedirectResource
2.32 +
2.33 +class OpenIDLoginResource(XSLFormsResource, OpenIDLoginUtils):
2.34 +
2.35 + """
2.36 + A login screen resource which should be modified or subclassed to define the
2.37 + following attributes:
2.38 +
2.39 + * resource_dir
2.40 + * template_resources - including a "login" entry for the login screen and
2.41 + a "success" entry for a screen indicating a
2.42 + successful login (used when redirects are not in
2.43 + use)
2.44 + * document_resources - including a "translations" entry
2.45 +
2.46 + The latter attribute is optional.
2.47 +
2.48 + The login template must define a "login" action, and provide a document
2.49 + structure where the login credentials can be found through this class's
2.50 + 'path_to_login_element' attribute (which can be overridden or modified).
2.51 + Such a structure would be as follows for the default configuration:
2.52 +
2.53 + <login username="..." password="..."/>
2.54 +
2.55 + The success template must provide a document structure where the location of
2.56 + the application can be found through this class's 'path_to_success_element'
2.57 + attribute (which can be overridden or modified). Such a structure would be
2.58 + as follows for the default configuration:
2.59 +
2.60 + <success location="..."/>
2.61 + """
2.62 +
2.63 + path_to_login_element = "/login"
2.64 + path_to_success_element = "/success"
2.65 +
2.66 + def __init__(self, app_url, authenticator, associations=None, use_redirect=1):
2.67 +
2.68 + """
2.69 + Initialise the resource with an 'app_url' and an 'authenticator'.
2.70 +
2.71 + The optional 'associations' is a mapping from association handles to
2.72 + secret keys.
2.73 +
2.74 + If the optional 'use_redirect' flag is set to a false value (which is
2.75 + not the default), a confirmation screen is given instead of immediately
2.76 + redirecting the user back to the original application.
2.77 +
2.78 + To get the root of the application, this resource needs an attribute on
2.79 + the transaction called "root".
2.80 + """
2.81 +
2.82 + OpenIDLoginUtils.__init__(self, associations, use_redirect)
2.83 + self.app_url = app_url
2.84 + self.authenticator = authenticator
2.85 +
2.86 + def select_activity(self, trans, form):
2.87 + form.set_activity("login")
2.88 +
2.89 + def respond_to_input(self, trans, form):
2.90 + parameters = form.get_parameters()
2.91 +
2.92 + # Test for login.
2.93 +
2.94 + if parameters.has_key("login"):
2.95 + self.check_login(trans, form)
2.96 +
2.97 + # Check for an OpenID signature verification request.
2.98 +
2.99 + elif parameters.get("openid.mode", [None])[0] == "check_authentication":
2.100 + self.check_authentication(trans, trans.get_fields())
2.101 +
2.102 + # NOTE: Permit association requests here.
2.103 + # Otherwise, show the login form.
2.104 +
2.105 + else:
2.106 + self.show_login(trans, form)
2.107 +
2.108 + # Methods called by the OpenID logic.
2.109 +
2.110 + def check_login(self, trans, form):
2.111 + doc = form.get_document()
2.112 + parameters = form.get_parameters()
2.113 +
2.114 + logelem = doc.xpath(self.path_to_login_element)[0]
2.115 + return_to = logelem.getAttribute("return_to") or parameters.get("openid.return_to", [""])[0]
2.116 + claimed_id = logelem.getAttribute("claimed_id") or parameters.get("openid.claimed_id", [""])[0]
2.117 + local_id = logelem.getAttribute("identity") or parameters.get("openid.identity", [""])[0]
2.118 +
2.119 + username = logelem.getAttribute("username")
2.120 + password = logelem.getAttribute("password")
2.121 +
2.122 + # If successful, switch to the success template and redirect.
2.123 + # NOTE: Permit flexibility in the credentials.
2.124 +
2.125 + if self.authenticator.authenticate(trans, (local_id, username), password):
2.126 + endpoint = self.app_url + trans.get_path_without_query()
2.127 + self.redirect_to_application(trans, form, claimed_id, local_id, username, return_to, endpoint)
2.128 + else:
2.129 + error = doc.createElement("error")
2.130 + logelem.appendChild(error)
2.131 + error.setAttribute("message", "Username or password not valid")
2.132 + self.show_login(trans, form)
2.133 +
2.134 + def redirect_to_application(self, trans, form, claimed_id, local_id, username, return_to, endpoint):
2.135 +
2.136 + """
2.137 + Redirect the client using 'trans', 'claimed_id', 'local_id', 'username'
2.138 + and the given 'return_to' and 'endpoint' details.
2.139 + """
2.140 +
2.141 + fields = self.get_openid_fields(trans, claimed_id, local_id, username, return_to, endpoint)
2.142 + url = self.get_openid_url(trans, fields)
2.143 +
2.144 + # Show the success page anyway.
2.145 + # Offer a POST-based form for redirection.
2.146 +
2.147 + self.show_success(trans, form, fields)
2.148 + if self.use_redirect:
2.149 + trans.redirect(url)
2.150 +
2.151 + def show_login(self, trans, form):
2.152 +
2.153 + """
2.154 + Writes a login screen using the transaction 'trans' and 'form',
2.155 + including details of the 'return_to' URL which the client was attempting
2.156 + to access, along with the 'claimed_id' and 'local_id'.
2.157 + """
2.158 +
2.159 + doc = form.get_document()
2.160 + parameters = form.get_parameters()
2.161 +
2.162 + logelem = doc.xpath(self.path_to_login_element)[0]
2.163 + return_to = logelem.getAttribute("return_to") or parameters.get("openid.return_to", [""])[0]
2.164 + claimed_id = logelem.getAttribute("claimed_id") or parameters.get("openid.claimed_id", [""])[0]
2.165 + local_id = logelem.getAttribute("identity") or parameters.get("openid.identity", [""])[0]
2.166 +
2.167 + logelem = doc.xpath(self.path_to_login_element)[0]
2.168 + logelem.setAttribute("return_to", return_to)
2.169 + logelem.setAttribute("claimed_id", claimed_id)
2.170 + logelem.setAttribute("identity", local_id)
2.171 +
2.172 + def show_success(self, trans, form, fields):
2.173 +
2.174 + """
2.175 + Writes a success screen using the transaction 'trans' and 'form', using
2.176 + a dictionary of 'fields' providing details of the transaction.
2.177 + """
2.178 +
2.179 + # Switch to the success activity.
2.180 +
2.181 + form.set_activity("success")
2.182 + doc = form.new_instance("success")
2.183 + successelem = doc.xpath(self.path_to_success_element)[0]
2.184 + successelem.setAttribute("location", fields["openid.return_to"][0])
2.185 +
2.186 + # Add OpenID fields.
2.187 +
2.188 + for name, values in fields.items():
2.189 + field = doc.createElement("field")
2.190 + field.setAttribute("name", name)
2.191 + field.setAttribute("value", values[0])
2.192 + successelem.appendChild(field)
2.193 +
2.194 + form.set_document(doc)
2.195 +
2.196 + # Output preparation.
2.197 +
2.198 + def create_output(self, trans, form):
2.199 + attributes = trans.get_attributes()
2.200 +
2.201 + stylesheet_parameters = {}
2.202 + references = {}
2.203 +
2.204 + # Set up translations.
2.205 +
2.206 + if self.document_resources.has_key("translations"):
2.207 + translations_xml = self.prepare_document("translations")
2.208 +
2.209 + try:
2.210 + language = trans.get_content_languages()[0]
2.211 + except IndexError:
2.212 + language = "en"
2.213 +
2.214 + stylesheet_parameters["locale"] = language
2.215 + references["translations"] = translations_xml
2.216 +
2.217 + # Complete the response.
2.218 +
2.219 + stylesheet_parameters["root"] = attributes["root"]
2.220 + XSLFormsResource.create_output(self, trans, form, stylesheet_parameters=stylesheet_parameters, references=references)
2.221 +
2.222 +# vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/XSLForms/Resources/WebResources.py Mon Nov 19 00:16:57 2007 +0000
3.2 +++ b/XSLForms/Resources/WebResources.py Mon Nov 19 00:18:17 2007 +0000
3.3 @@ -380,15 +380,18 @@
3.4 the current document.
3.5 """
3.6
3.7 + activity = form.get_activity()
3.8 +
3.9 # Transform, adding enumerations/ranges.
3.10
3.11 - init_xsl = self.prepare_initialiser(form.get_activity())
3.12 - form.set_document(
3.13 - self.get_result(
3.14 - [init_xsl], form.get_document(), stylesheet_parameters,
3.15 - stylesheet_expressions, references
3.16 + if self.init_resources.has_key(activity):
3.17 + init_xsl = self.prepare_initialiser(activity)
3.18 + form.set_document(
3.19 + self.get_result(
3.20 + [init_xsl], form.get_document(), stylesheet_parameters,
3.21 + stylesheet_expressions, references
3.22 + )
3.23 )
3.24 - )
3.25
3.26 def respond_to_document(self, trans, form):
3.27