1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/XSLForms/Resources/OpenIDInitiation.py Sun Feb 03 20:04:44 2008 +0000
1.3 @@ -0,0 +1,210 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +OpenID initiation resources for XSLForms applications. These resources use
1.8 +"root" attributes on transaction objects, and therefore should be defined within
1.9 +the appropriate resources in site maps.
1.10 +
1.11 +Copyright (C) 2006, 2007, 2008 Paul Boddie <paul@boddie.org.uk>
1.12 +
1.13 +This program is free software; you can redistribute it and/or modify it under
1.14 +the terms of the GNU Lesser General Public License as published by the Free
1.15 +Software Foundation; either version 3 of the License, or (at your option) any
1.16 +later version.
1.17 +
1.18 +This program is distributed in the hope that it will be useful, but WITHOUT
1.19 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.20 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1.21 +details.
1.22 +
1.23 +You should have received a copy of the GNU Lesser General Public License along
1.24 +with this program. If not, see <http://www.gnu.org/licenses/>.
1.25 +"""
1.26 +
1.27 +from WebStack.Generic import ContentType, EndOfResponse
1.28 +from WebStack.Resources.OpenIDInitiation import OpenIDInitiationUtils
1.29 +from XSLForms.Resources.WebResources import XSLFormsResource
1.30 +
1.31 +class OpenIDInitiationResource(XSLFormsResource, OpenIDInitiationUtils):
1.32 +
1.33 + """
1.34 + An initiation screen resource which should be modified or subclassed to
1.35 + define the following attributes:
1.36 +
1.37 + * resource_dir
1.38 + * template_resources - including an "initiation" entry for the initiation
1.39 + screen and a "success" entry for a screen
1.40 + indicating successful redirection to a provider
1.41 + (used when redirects are not in use)
1.42 + * document_resources - including a "translations" entry
1.43 +
1.44 + The latter attribute is optional.
1.45 +
1.46 + The initiation template must define an "initiation" action, and provide a
1.47 + document structure where the identity credentials can be found through this
1.48 + class's 'path_to_identity_element' attribute (which can be overridden or
1.49 + modified). Such a structure would be as follows for the default
1.50 + configuration:
1.51 +
1.52 + <initiation identity="..."/>
1.53 +
1.54 + The success template must provide a document structure where the location of
1.55 + the application can be found through this class's 'path_to_success_element'
1.56 + attribute (which can be overridden or modified). Such a structure would be
1.57 + as follows for the default configuration:
1.58 +
1.59 + <success mode="..." return_to="..." claimed_id="..." identity="..."/>
1.60 + """
1.61 +
1.62 + path_to_initiation_element = "/initiation"
1.63 + path_to_success_element = "/success"
1.64 +
1.65 + def __init__(self, openid_mode=None, use_redirect=1):
1.66 +
1.67 + """
1.68 + Initialise the resource.
1.69 +
1.70 + The optional 'openid_mode' parameter may be set to "checkid_immediate"
1.71 + or "checkid_setup" (the default).
1.72 +
1.73 + If the optional 'use_redirect' flag is set to a false value (which is
1.74 + not the default), a confirmation screen is given instead of immediately
1.75 + redirecting the user to the OpenID provider.
1.76 +
1.77 + To get the root of the application, this resource needs an attribute on
1.78 + the transaction called "root".
1.79 + """
1.80 +
1.81 + OpenIDInitiationUtils.__init__(self, openid_mode, use_redirect)
1.82 +
1.83 + def select_activity(self, trans, form):
1.84 + form.set_activity("initiation")
1.85 +
1.86 + def respond_to_input(self, trans, form):
1.87 + parameters = form.get_parameters()
1.88 +
1.89 + if parameters.has_key("app"):
1.90 + app = parameters["app"]
1.91 + else:
1.92 + app = trans.get_fields_from_path().get("app", [""])[0]
1.93 +
1.94 + if parameters.has_key("initiate"):
1.95 + self.check_identity(trans, form, app)
1.96 + # The above method does not return.
1.97 +
1.98 + # Otherwise, show the initiation form.
1.99 +
1.100 + self.show_initiation(trans, form, app)
1.101 +
1.102 + # Methods called by the OpenID logic.
1.103 +
1.104 + def check_identity(self, trans, form, app):
1.105 +
1.106 + """
1.107 + Check the identity found through 'trans' and 'fields', using 'app' and
1.108 + discovered information about the identity to redirect to the provider.
1.109 + """
1.110 +
1.111 + doc = form.get_document()
1.112 + parameters = form.get_parameters()
1.113 +
1.114 + initelem = doc.xpath(self.path_to_initiation_element)[0]
1.115 + identity = initelem.getAttribute("identity") or parameters.get("identity", [""])[0]
1.116 + claimed_identifier, provider, local_identifier = self.get_provider_url(trans, identity)
1.117 +
1.118 + if provider is not None:
1.119 + self.redirect_to_provider(trans, form, app, claimed_identifier, provider, local_identifier)
1.120 +
1.121 + def redirect_to_provider(self, trans, form, app, claimed_identifier, provider, local_identifier):
1.122 +
1.123 + """
1.124 + Redirect the client using 'trans', 'form' and the given 'app',
1.125 + 'claimed_identifier', 'provider' and 'local_identifier' details.
1.126 +
1.127 + See:
1.128 + http://openid.net/specs/openid-authentication-2_0-12.html#rfc.section.5.2
1.129 + http://openid.net/specs/openid-authentication-2_0-12.html#rfc.section.9
1.130 + """
1.131 +
1.132 + url = self.get_redirect_url(trans, app, claimed_identifier, provider, local_identifier)
1.133 +
1.134 + # Show the success page anyway.
1.135 + # Offer a POST-based form for redirection.
1.136 +
1.137 + self.show_success(trans, form, provider, app, claimed_identifier, local_identifier)
1.138 +
1.139 + # Redirect to the OpenID provider URL.
1.140 +
1.141 + if self.use_redirect:
1.142 + trans.redirect(url)
1.143 + else:
1.144 + raise WebStack.Generic.EndOfResponse
1.145 +
1.146 + def show_initiation(self, trans, form, app):
1.147 +
1.148 + """
1.149 + Writes a initiation screen using the transaction 'trans' and 'form',
1.150 + including details of the 'app' which the client was attempting to
1.151 + access.
1.152 + """
1.153 +
1.154 + doc = form.get_document()
1.155 + parameters = form.get_parameters()
1.156 +
1.157 + initelem = doc.xpath(self.path_to_initiation_element)[0]
1.158 + identity = initelem.getAttribute("identity") or parameters.get("identity", [""])[0]
1.159 + app = initelem.getAttribute("app") or parameters.get("app", [""])[0]
1.160 +
1.161 + initelem = doc.xpath(self.path_to_initiation_element)[0]
1.162 + initelem.setAttribute("identity", identity)
1.163 + initelem.setAttribute("app", app)
1.164 +
1.165 + def show_success(self, trans, form, provider, app, claimed_identifier, local_identifier):
1.166 +
1.167 + """
1.168 + Writes a success screen using the transaction 'trans' and 'form',
1.169 + including details of the OpenID 'provider', the 'app' URL,
1.170 + 'claimed_identifier' and 'local_identifier'.
1.171 + """
1.172 +
1.173 + # Switch to the success activity.
1.174 +
1.175 + form.set_activity("success")
1.176 + doc = form.new_instance("success")
1.177 + successelem = doc.xpath(self.path_to_success_element)[0]
1.178 + successelem.setAttribute("provider", provider)
1.179 + successelem.setAttribute("ns", self.openid_ns)
1.180 + successelem.setAttribute("mode", self.openid_mode)
1.181 + successelem.setAttribute("return_to", app)
1.182 + successelem.setAttribute("claimed_id", claimed_identifier)
1.183 + successelem.setAttribute("identity", local_identifier)
1.184 +
1.185 + form.set_document(doc)
1.186 +
1.187 + # Output preparation.
1.188 +
1.189 + def create_output(self, trans, form):
1.190 + attributes = trans.get_attributes()
1.191 +
1.192 + stylesheet_parameters = {}
1.193 + references = {}
1.194 +
1.195 + # Set up translations.
1.196 +
1.197 + if self.document_resources.has_key("translations"):
1.198 + translations_xml = self.prepare_document("translations")
1.199 +
1.200 + try:
1.201 + language = trans.get_content_languages()[0]
1.202 + except IndexError:
1.203 + language = "en"
1.204 +
1.205 + stylesheet_parameters["locale"] = language
1.206 + references["translations"] = translations_xml
1.207 +
1.208 + # Complete the response.
1.209 +
1.210 + stylesheet_parameters["root"] = attributes["root"]
1.211 + XSLFormsResource.create_output(self, trans, form, stylesheet_parameters=stylesheet_parameters, references=references)
1.212 +
1.213 +# vim: tabstop=4 expandtab shiftwidth=4