XSLTools

XSLForms/Resources/OpenIDInitiation.py

687:ae7bdbf61e32
2009-06-22 Paul Boddie Added some error handling to the questionnaire application.
     1 #!/usr/bin/env python     2      3 """     4 OpenID initiation resources for XSLForms applications. These resources use     5 "root" attributes on transaction objects, and therefore should be defined within     6 the appropriate resources in site maps.     7      8 Copyright (C) 2006, 2007, 2008 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 from WebStack.Resources.OpenIDInitiation import OpenIDInitiationUtils    26 from XSLForms.Resources.WebResources import XSLFormsResource    27     28 class OpenIDInitiationResource(XSLFormsResource, OpenIDInitiationUtils):    29     30     """    31     An initiation screen resource which should be modified or subclassed to    32     define the following attributes:    33     34       * resource_dir    35       * template_resources - including an "initiation" entry for the initiation    36                              screen and a "success" entry for a screen    37                              indicating successful redirection to a provider    38                              (used when redirects are not in use)    39       * document_resources - including a "translations" entry    40     41     The latter attribute is optional.    42     43     The initiation template must define an "initiation" action, and provide a    44     document structure where the identity credentials can be found through this    45     class's 'path_to_identity_element' attribute (which can be overridden or    46     modified). Such a structure would be as follows for the default    47     configuration:    48     49     <initiation identity="..."/>    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 mode="..." return_to="..." claimed_id="..." identity="..."/>    57     """    58     59     path_to_initiation_element = "/initiation"    60     path_to_success_element = "/success"    61     62     def __init__(self, openid_mode=None, use_redirect=1):    63     64         """    65         Initialise the resource.    66     67         The optional 'openid_mode' parameter may be set to "checkid_immediate"    68         or "checkid_setup" (the default).    69     70         If the optional 'use_redirect' flag is set to a false value (which is    71         not the default), a confirmation screen is given instead of immediately    72         redirecting the user to the OpenID provider.    73     74         To get the root of the application, this resource needs an attribute on    75         the transaction called "root".    76         """    77     78         OpenIDInitiationUtils.__init__(self, openid_mode, use_redirect)    79     80     def select_activity(self, trans, form):    81         form.set_activity("initiation")    82     83     def respond_to_input(self, trans, form):    84         parameters = form.get_parameters()    85     86         if parameters.has_key("app"):    87             app = parameters["app"]    88         else:    89             app = trans.get_fields_from_path().get("app", [""])[0]    90     91         if parameters.has_key("initiate"):    92             self.check_identity(trans, form, app)    93             # The above method does not return.    94     95         # Otherwise, show the initiation form.    96     97         self.show_initiation(trans, form, app)    98     99     # Methods called by the OpenID logic.   100    101     def check_identity(self, trans, form, app):   102    103         """   104         Check the identity found through 'trans' and 'fields', using 'app' and   105         discovered information about the identity to redirect to the provider.   106         """   107    108         doc = form.get_document()   109         parameters = form.get_parameters()   110    111         initelem = doc.xpath(self.path_to_initiation_element)[0]   112         identity = initelem.getAttribute("identity") or parameters.get("identity", [""])[0]   113         claimed_identifier, provider, local_identifier = self.get_provider_url(trans, identity)   114    115         if provider is not None:   116             self.redirect_to_provider(trans, form, app, claimed_identifier, provider, local_identifier)   117    118     def redirect_to_provider(self, trans, form, app, claimed_identifier, provider, local_identifier):   119    120         """   121         Redirect the client using 'trans', 'form' and the given 'app',   122         'claimed_identifier', 'provider' and 'local_identifier' details.   123    124         See:   125         http://openid.net/specs/openid-authentication-2_0-12.html#rfc.section.5.2   126         http://openid.net/specs/openid-authentication-2_0-12.html#rfc.section.9   127         """   128    129         url = self.get_redirect_url(trans, app, claimed_identifier, provider, local_identifier)   130    131         # Show the success page anyway.   132         # Offer a POST-based form for redirection.   133    134         self.show_success(trans, form, provider, app, claimed_identifier, local_identifier)   135    136         # Redirect to the OpenID provider URL.   137    138         if self.use_redirect:   139             trans.redirect(url)   140         else:   141             raise WebStack.Generic.EndOfResponse   142    143     def show_initiation(self, trans, form, app):   144    145         """   146         Writes a initiation screen using the transaction 'trans' and 'form',   147         including details of the 'app' which the client was attempting to   148         access.   149         """   150    151         doc = form.get_document()   152         parameters = form.get_parameters()   153    154         initelem = doc.xpath(self.path_to_initiation_element)[0]   155         identity = initelem.getAttribute("identity") or parameters.get("identity", [""])[0]   156         app = initelem.getAttribute("app") or parameters.get("app", [""])[0]   157    158         initelem = doc.xpath(self.path_to_initiation_element)[0]   159         initelem.setAttribute("identity", identity)   160         initelem.setAttribute("app", app)   161    162     def show_success(self, trans, form, provider, app, claimed_identifier, local_identifier):   163    164         """   165         Writes a success screen using the transaction 'trans' and 'form',   166         including details of the OpenID 'provider', the 'app' URL,   167         'claimed_identifier' and 'local_identifier'.   168         """   169    170         # Switch to the success activity.   171    172         form.set_activity("success")   173         doc = form.new_instance("success")   174         successelem = doc.xpath(self.path_to_success_element)[0]   175         successelem.setAttribute("provider", provider)   176         successelem.setAttribute("ns", self.openid_ns)   177         successelem.setAttribute("mode", self.openid_mode)   178         successelem.setAttribute("return_to", app)   179         successelem.setAttribute("claimed_id", claimed_identifier)   180         successelem.setAttribute("identity", local_identifier)   181    182         form.set_document(doc)   183    184     # Output preparation.   185    186     def create_output(self, trans, form):   187         attributes = trans.get_attributes()   188    189         stylesheet_parameters = {}   190         references = {}   191    192         # Set up translations.   193    194         if self.document_resources.has_key("translations"):   195             translations_xml = self.prepare_document("translations")   196    197             try:   198                 language = trans.get_content_languages()[0]   199             except IndexError:   200                 language = "en"   201    202             stylesheet_parameters["locale"] = language   203             references["translations"] = translations_xml   204    205         # Complete the response.   206    207         stylesheet_parameters["root"] = attributes["root"]   208         XSLFormsResource.create_output(self, trans, form, stylesheet_parameters=stylesheet_parameters, references=references)   209    210 # vim: tabstop=4 expandtab shiftwidth=4