Changeset 6243


Ignore:
Timestamp:
23/12/09 17:03:55 (10 years ago)
Author:
pjkersha
Message:

Cleaned up the decide page interface of the OpenID Provider and added OpenIDResponse object as input so that AX values to be returned can be displayed to the user.

Location:
TI12-security/trunk/NDGSecurity/python
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/NDGSecurity/python/Makefile

    r5727 r6243  
    1212# $Id$ 
    1313EGG_DIRS=ndg_security_common ndg_security_client ndg_security_server \ 
    14 ndg_security_test ndg_security ndg_security_saml 
     14ndg_security_test ndg_security 
    1515 
    1616# Override on the command line for alternative path 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/__init__.py

    r6202 r6243  
    625625        in the decide page interface. 
    626626         
    627          
    628627        @type environ: dict 
    629628        @param environ: dictionary of environment variables 
     
    632631        @rtype: basestring 
    633632        @return: WSGI response 
    634  
    635         """ 
    636          
     633        """  
    637634        oidRequest = self.session.get( 
    638                     OpenIDProviderMiddleware.LAST_CHECKID_REQUEST_SESSION_KEYNAME) 
     635                OpenIDProviderMiddleware.LAST_CHECKID_REQUEST_SESSION_KEYNAME) 
    639636        if oidRequest is None: 
    640637            log.error("Suspected do_allow called from stale request") 
     
    746743        @return: WSGI response 
    747744        """ 
     745        fail2URI = self.query.get('fail_to') 
    748746         
    749747        if 'submit' in self.query: 
    750748            if 'username' in self.query: 
    751                 # login 
    752                 if OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME in \ 
    753                    self.session: 
    754                     log.error("Attempting login for user %s: user is already " 
    755                               "logged in", self.session[ 
    756                             OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME]) 
    757                      
    758                     return self._redirect(start_response, 
    759                                           self.query['fail_to']) 
     749                return self.__loginSubmit(environ, start_response) 
     750            else: 
     751                return self.__logoutSubmit(environ, start_response) 
     752         
     753        else: 
     754            if 'cancel' not in self.query: 
     755                log.error('Login input not recognised: %r' % self.query) 
    760756                 
    761                 oidRequest = self.session.get( 
     757            if fail2URI is None: 
     758                log.error("No 'fail_to' field set in Login POST: %r" %  
     759                          self.query) 
     760                return self._render.errorPage(environ, start_response, 
     761                    "An internal error occurred possibly due to a request " 
     762                    "that's expired.  Please retry from the site where " 
     763                    "you entered your OpenID.  If the problem persists " 
     764                    "report it to your site administrator.")                 
     765            else: 
     766                return self._redirect(start_response, fail2URI)   
     767         
     768    def __loginSubmit(self, environ, start_response): 
     769        """Helper method to do_loginsubmit - handles 'username' field in login  
     770        form POST 
     771         
     772        @type environ: dict 
     773        @param environ: dictionary of environment variables 
     774        @type start_response: callable 
     775        @param start_response: standard WSGI callable to set HTTP headers 
     776        @rtype: basestring 
     777        @return: WSGI response 
     778        """ 
     779        if (OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME in  
     780            self.session): 
     781            log.error("Attempting login for user %s: user is already " 
     782                      "logged in", self.session[ 
     783                    OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME]) 
     784             
     785            return self._redirect(start_response, 
     786                                  self.query['fail_to']) 
     787         
     788        oidRequest = self.session.get( 
    762789                OpenIDProviderMiddleware.LAST_CHECKID_REQUEST_SESSION_KEYNAME) 
     790         
     791        if oidRequest is None: 
     792            log.error("Getting OpenID request for login - No request " 
     793                      "found in session") 
     794            return self._render.errorPage(environ, start_response, 
     795                "An internal error occurred possibly due to a request " 
     796                "that's expired.  Please retry from the site where " 
     797                "you entered your OpenID.  If the problem persists " 
     798                "report it to your site administrator.") 
     799             
     800        # Get user identifier to check against credentials provided 
     801        if oidRequest.idSelect(): 
     802            # ID select mode enables the user to request specifying 
     803            # their OpenID Provider without giving a personal user URL  
     804            try: 
     805                userIdentifiers = self._authN.username2UserIdentifiers( 
     806                                                environ, 
     807                                                self.query['username']) 
     808            except Exception: 
     809                log.error("Associating username %r with OpenID URL: %s"%  
     810                          (self.query.get('username'), 
     811                           traceback.format_exc())) 
     812                msg = ("An internal error occured matching an OpenID " 
     813                       "to your account.  If the problem persists " 
     814                       "contact your system administrator.") 
     815 
     816                response = self._render.errorPage(environ,  
     817                                                  start_response, 
     818                                                  msg)  
     819                return response 
     820 
     821            if not isinstance(userIdentifiers, (list, tuple)): 
     822                log.error("Unexpected type %r returned from %r for " 
     823                          "user identifiers; expecting list or tuple" 
     824                          % (type(userIdentifiers), type(self._authN))) 
     825                           
     826                return self._render.errorPage(environ, start_response, 
     827                    "An internal error occurred setting your default " 
     828                    "OpenID URL.  Please retry from the site where " 
     829                    "you entered your OpenID providing your full " 
     830                    "identity URL.  If the problem persists report it " 
     831                    "to your site administrator.") 
    763832                 
    764                 if oidRequest is None: 
    765                     log.error("Getting OpenID request for login - No request " 
    766                               "found in session") 
    767                     return self._render.errorPage(environ, start_response, 
    768                         "An internal error occurred possibly due to a request " 
    769                         "that's expired.  Please retry from the site where " 
    770                         "you entered your OpenID.  If the problem persists " 
    771                         "report it to your site administrator.") 
    772                      
    773                 # Get user identifier to check against credentials provided 
    774                 if oidRequest.idSelect(): 
    775                     # ID select mode enables the user to request specifying 
    776                     # their OpenID Provider without giving a personal user URL  
    777                     userIdentifiers = self._authN.username2UserIdentifiers( 
    778                                                         environ, 
    779                                                         self.query['username']) 
    780                     if not isinstance(userIdentifiers, (list, tuple)): 
    781                         log.error("Unexpected type %r returned from %r for " 
    782                                   "user identifiers; expecting list or tuple" 
    783                                   % (type(userIdentifiers), type(self._authN))) 
    784                                    
    785                         return self._render.errorPage(environ, start_response, 
    786                             "An internal error occurred setting your default " 
    787                             "OpenID URL.  Please retry from the site where " 
    788                             "you entered your OpenID providing your full " 
    789                             "identity URL.  If the problem persists report it " 
    790                             "to your site administrator.") 
    791                          
    792                     # FIXME: Assume the *first* user identifier entry is the 
    793                     # one to use.  The user could have multiple identifiers 
    794                     # but in practice it's more manageable to have a single one 
    795                     identityURI = self.createIdentityURI(self.identityUriTmpl, 
    796                                                          userIdentifiers[0]) 
    797                 else: 
    798                     # Get the unique user identifier from the user's OpenID URL 
    799                     identityURI = oidRequest.identity 
    800                      
    801                 # Invoke custom authentication interface plugin 
    802                 try: 
    803                     self._authN.logon(environ, 
    804                                       identityURI, 
    805                                       self.query['username'], 
    806                                       self.query.get('password', '')) 
    807                      
    808                 except AuthNInterfaceError, e: 
    809                     return self._render.login(environ, start_response, 
    810                                             msg=e.userMsg, 
    811                                             success_to=self.urls['url_decide'])                    
    812                 except Exception, e: 
    813                     log.error("Unexpected %s type exception raised during " 
    814                               "authentication: %s", type(e), 
    815                               traceback.format_exc()) 
    816                     msg = ("An internal error occurred.  " 
    817                            "Please try again or if the problems persists " 
    818                            "contact your system administrator.") 
    819  
    820                     response = self._render.login(environ, start_response, 
    821                                           msg=msg, 
    822                                           success_to=self.urls['url_decide']) 
    823                     return response 
    824                         
    825                 self.session[ 
    826                     OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME 
    827                 ] = self.query['username'] 
    828                  
    829                 self.session[ 
    830                     OpenIDProviderMiddleware.IDENTITY_URI_SESSION_KEYNAME 
    831                 ] = identityURI 
    832                  
    833                 self.session[ 
    834                     OpenIDProviderMiddleware.APPROVED_FLAG_SESSION_KEYNAME] = {} 
    835                      
    836                 self.session.save() 
    837                  
    838                 log.info("user [%s] logged in", self.session[ 
    839                         OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME]) 
    840             else: 
    841                 # logout 
    842                 if OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME not in \ 
    843                    self.session: 
    844                     log.error("No user is logged in") 
    845                     return self._redirect(start_response,  
    846                                           self.query['fail_to']) 
    847                  
    848                 log.info("user [%s] logging out ...", self.session[ 
    849                         OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME]) 
    850  
    851                 del self.session[ 
    852                         OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME] 
    853                 self.session.pop( 
    854                         OpenIDProviderMiddleware.APPROVED_FLAG_SESSION_KEYNAME,  
    855                         None) 
    856                 self.session.save() 
    857                  
    858                 try: 
    859                     self._authN.logout() 
    860                      
    861                 except Exception: 
    862                     log.error("Unexpected exception raised during " 
    863                               "logout: %s" % traceback.format_exc()) 
    864                     msg = ("An internal error occured during logout.  If the " 
    865                            "problem persists contact your system " 
    866                            "administrator.") 
    867  
    868                     response = self._render.errorPage(environ, start_response, 
    869                                                       msg)  
    870                     return response 
    871                  
    872             return self._redirect(start_response, self.query['success_to']) 
    873          
    874         elif 'cancel' in self.query: 
     833            # FIXME: Assume the *first* user identifier entry is the 
     834            # one to use.  The user could have multiple identifiers 
     835            # but in practice it's more manageable to have a single one 
     836            identityURI = self.createIdentityURI(self.identityUriTmpl, 
     837                                                 userIdentifiers[0]) 
     838        else: 
     839            # Get the unique user identifier from the user's OpenID URL 
     840            identityURI = oidRequest.identity 
     841             
     842        # Invoke custom authentication interface plugin 
     843        try: 
     844            self._authN.logon(environ, 
     845                              identityURI, 
     846                              self.query['username'], 
     847                              self.query.get('password', '')) 
     848             
     849        except AuthNInterfaceError, e: 
     850            return self._render.login(environ,  
     851                                      start_response, 
     852                                      msg=e.userMsg, 
     853                                      success_to=self.urls['url_decide'])                    
     854        except Exception, e: 
     855            log.error("Unexpected %s type exception raised during " 
     856                      "authentication: %s", type(e), 
     857                      traceback.format_exc()) 
     858            msg = ("An internal error occurred.  " 
     859                   "Please try again or if the problems persists " 
     860                   "contact your system administrator.") 
     861 
     862            response = self._render.login(environ, start_response, 
     863                                  msg=msg, 
     864                                  success_to=self.urls['url_decide']) 
     865            return response 
     866         
     867        # Update session details       
     868        self.session[ 
     869            OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME 
     870        ] = self.query['username'] 
     871         
     872        self.session[ 
     873            OpenIDProviderMiddleware.IDENTITY_URI_SESSION_KEYNAME] = identityURI 
     874                
     875        self.session[ 
     876            OpenIDProviderMiddleware.APPROVED_FLAG_SESSION_KEYNAME] = {} 
     877             
     878        self.session.save() 
     879         
     880        log.info("user [%s] logged in", self.session[ 
     881                 OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME]) 
     882         
     883        return self._redirect(start_response, self.query['success_to']) 
     884         
     885    def __logoutSubmit(self, environ, start_response): 
     886        """Logout helper method to do_loginsubmit - triggered when 'submit'  
     887        field set in login POST action but no 'username' field set 
     888         
     889        @type environ: dict 
     890        @param environ: dictionary of environment variables 
     891        @type start_response: callable 
     892        @param start_response: standard WSGI callable to set HTTP headers 
     893        @rtype: basestring 
     894        @return: WSGI response 
     895        """ 
     896        if (OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME not in  
     897            self.session): 
     898            log.error("No user is logged in") 
    875899            return self._redirect(start_response, self.query['fail_to']) 
    876         else: 
    877             log.error('Login input not recognised %r' % self.query) 
    878             return self._redirect(start_response, self.query['fail_to'])   
    879  
     900         
     901        log.info("user [%s] logging out ...", self.session[ 
     902                 OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME]) 
     903 
     904        del self.session[OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME] 
     905        self.session.pop(OpenIDProviderMiddleware.APPROVED_FLAG_SESSION_KEYNAME,  
     906                         None) 
     907        self.session.save() 
     908         
     909        try: 
     910            self._authN.logout() 
     911             
     912        except Exception: 
     913            log.error("Unexpected exception raised during logout: %s" %  
     914                      traceback.format_exc()) 
     915            msg = ("An internal error occured during logout.  If the problem " 
     916                   "persists contact your system administrator.") 
     917 
     918            response = self._render.errorPage(environ, start_response, msg)  
     919            return response 
     920             
     921        return self._redirect(start_response, self.query['success_to']) 
     922     
    880923    def do_mainpage(self, environ, start_response): 
    881924        '''Show an information page about the OpenID Provider 
     
    920963                                          "administrator.", 
    921964                                          code=400) 
     965             
     966        # Prepare a response with any additional AX or SReg parameters appended 
     967        # so that the decide page can if required show these to the user for 
     968        # review before return to the RP. 
     969        identityURI = self.session[ 
     970            OpenIDProviderMiddleware.IDENTITY_URI_SESSION_KEYNAME] 
     971         
     972        oidResponse = self._identityApprovedPostProcessing(oidRequest, 
     973                                                        identifier=identityURI) 
    922974         
    923975        try: 
    924976            return self._render.decidePage(environ,  
    925977                                           start_response,  
    926                                            oidRequest) 
     978                                           oidRequest, 
     979                                           oidResponse) 
    927980        except AuthNInterfaceError, e: 
    928981            log.error("%s type exception raised calling decide page " 
     
    12611314    """Error with configuration settings.  Raise from __init__""" 
    12621315    errorMsg = "RenderingInterface configuration error"     
    1263      
    1264      
     1316 
     1317  
    12651318class RenderingInterface(object): 
    12661319    """Interface class for rendering of OpenID Provider pages.  It implements 
     
    14571510                        ('Content-length', str(len(response)))]) 
    14581511        return response 
    1459      
    1460  
    1461     def decidePage(self, environ, start_response, oidRequest): 
     1512 
     1513    def decidePage(self, environ, start_response, oidRequest, oidResponse): 
    14621514        """Show page giving the user the option to approve the return of their 
    14631515        credentials to the Relying Party.  This page is also displayed for 
     
    14871539        @type oidRequest: openid.server.server.CheckIDRequest 
    14881540        @param oidRequest: OpenID Check ID Request object 
     1541        @type oidResponse: openid.server.server.OpenIDResponse 
     1542        @param oidResponse: OpenID response object 
    14891543        @rtype: basestring 
    14901544        @return: WSGI response 
     
    14951549                        ('Content-length', str(len(response)))]) 
    14961550        return response 
    1497  
    14981551 
    14991552    def errorPage(self, environ, start_response, msg, code=500): 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/renderinginterface/buffet/__init__.py

    r6069 r6243  
    158158 
    159159    
    160     def decidePage(self, environ, start_response, oidRequest): 
     160    def decidePage(self, environ, start_response, oidRequest, oidResponse): 
    161161        """Handle user interaction required before final submit back to Relying 
    162162        Party 
    163163        @type oidRequest: openid.server.server.CheckIDRequest 
    164164        @param oidRequest: OpenID Check ID Request object 
     165        @type oidResponse: openid.server.server.OpenIDResponse 
     166        @param oidResponse: OpenID response object 
    165167        """ 
    166168        self.title = 'Approve OpenID Request?' 
    167169        self.trust_root = oidRequest.trust_root 
    168170        self.oidRequest = oidRequest 
     171        self.oidResponse = oidResponse 
    169172        self.environ = environ 
    170173         
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/renderinginterface/demo.py

    r6069 r6243  
    159159     
    160160 
    161     def decidePage(self, environ, start_response, oidRequest): 
     161    def decidePage(self, environ, start_response, oidRequest, oidResponse): 
    162162        """Show page giving the user the option to approve the return of their 
    163163        credentials to the Relying Party.  This page is also displayed for 
     
    173173        @type oidRequest: openid.server.server.CheckIDRequest 
    174174        @param oidRequest: OpenID Check ID Request object 
     175        @type oidResponse: openid.server.server.OpenIDResponse 
     176        @param oidResponse: OpenID response object 
    175177        @rtype: basestring 
    176178        @return: WSGI response 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/renderinginterface/genshi/__init__.py

    r6202 r6243  
    5858        'environ', 
    5959        'identityURI', 
    60         'oidRequest' 
     60        'oidRequest', 
     61        'oidResponse' 
    6162    ) 
    6263    __slots__ = tuple(["__%s" % name for name in ATTR_NAMES]) 
     
    109110         
    110111        self.__oidRequest = None 
     112        self.__oidResponse = None 
    111113        self.__identityURI = None 
    112114        self.__environ = None 
     
    130132    def getOidRequest(self): 
    131133        return self.__oidRequest 
     134 
     135    def getOidResponse(self): 
     136        return self.__oidResponse 
    132137 
    133138    def setTrust_root(self, value): 
     
    142147                            'got %r' % (CheckIDRequest, type(value))) 
    143148        self.__oidRequest = value 
     149 
     150    def setOidResponse(self, value): 
     151        if not isinstance(value, OpenIDResponse): 
     152            raise TypeError('Expecting %r type for oidResponse attribute; ' 
     153                            'got %r' % (OpenIDResponse, type(value))) 
     154        self.__oidResponse = value 
    144155 
    145156    def getSuccess_to(self): 
     
    349360        return response 
    350361   
    351     def decidePage(self, environ, start_response, oidRequest): 
     362    def decidePage(self, environ, start_response, oidRequest, oidResponse): 
    352363        """Handle user interaction required before final submit back to Relying 
    353364        Party""" 
     
    356367        self.trust_root = oidRequest.trust_root 
    357368        self.oidRequest = oidRequest 
     369        self.oidResponse = oidResponse 
    358370        ax_req = ax.FetchRequest.fromOpenIDRequest(oidRequest) 
    359371        axRequestedAttr = ax_req.requested_attributes 
     
    408420                          doc="oidRequest - OpenID Request object") 
    409421 
     422    oidResponse = property(getOidResponse, setOidResponse,  
     423                           doc="oidRequest - OpenID Response object") 
     424    
    410425    environ = property(getEnviron, setEnviron, None,  
    411426                       "WSGI environ dict") 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/renderinginterface/genshi/templates/decide.html

    r6202 r6243  
    1616                                        <td> 
    1717                                                The website <b>$c.oidRequest.trust_root</b> has requested  
    18                                                 your OpenID: 
     18                                                your OpenID for sign in: 
    1919                                        </td> 
    2020                                </tr> 
     
    2626                                <tr py:if="len(axRequestedAttr) > 0"> 
    2727                                    <td> 
    28                                                 <p>$c.oidRequest.trust_root has requested these additional items of information.  Optional  
    29                                                 items may be omitted from the response by unchecking the relevant checkboxes:</p> 
     28                                                This site has also requested some additional information: 
    3029                                         <table id="opAXRequestedAttributes"> 
    31                                              <tbody> 
    32                                                 <th> 
    33                                                     <td>Item</td> 
    34                                                     <td>Return Item to Requesting Site?</td> 
    35                                                 </th> 
    36                                                                                 <tr py:for="i in axRequestedAttr.values()"> 
    37                                                                                     <td>${i.alias or i.type_uri}</td> 
    38                                                                                     <td py:if="i.required">&nbsp;</td> 
    39                                                                                     <td py:if="not i.required"><input  type="checkbox" id="${i}.returnToRP" name="${i}.returnToRP" checked="checked" value="yes"/></td> 
    40                                                                                 </tr>  
    41                                                                  </tbody> 
     30                                                <tr> 
     31                                                    <th>Item</th> 
     32                                                    <th>Return Item to Requesting Site?</th> 
     33                                                </tr> 
     34                                                                        <tr py:for="i in axRequestedAttr.values()"> 
     35                                                                            <td>${i.alias or i.type_uri}</td> 
     36                                                                            <td py:if="i.required"><input type="checkbox" id="${i}.returnToRP" name="${i}.returnToRP" checked="checked" value="yes" disabled="disabled"/></td> 
     37                                                                            <td py:if="not i.required"><input type="checkbox" id="${i}.returnToRP" name="${i}.returnToRP" checked="checked" value="yes"/></td> 
     38                                                                        </tr>  
    4239                                                            </table> 
    4340                                    </td> 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/relyingparty/signin_interface/genshi/public/layout/default.css

    r6202 r6243  
    2020        width: 100%; 
    2121        border-collapse: collapse; 
    22         background-color: #eef; 
     22        background-color: #e6f0f8;  
    2323        table-layout: auto; 
     24        margin-top:20px;  
     25    margin-bottom: 20px;  
    2426} 
    2527 
    2628#opAXRequestedAttributes td, #opAXRequestedAttributes th  
    2729{ 
    28 font-size:1em; 
    29 border:1px solid #dde; 
    30 padding:3px 7px 2px 7px; 
     30        font-size:0.9em; 
     31        border:1px solid #ffffff; 
     32        padding:3px 7px 2px 7px; 
    3133} 
    3234 
    3335#opAXRequestedAttributes th  
    3436{ 
    35 font-size:1.1em; 
    36 text-align:left; 
    37 padding-top:5px; 
    38 padding-bottom:4px; 
    39 background-color: #ccd; 
    40 color:#ffffff; 
     37        font-size:1.0em; 
     38        text-align:left; 
     39        padding-top:5px; 
     40        padding-bottom:4px; 
     41        background-color: #cedbe5; 
     42        color: #333; 
    4143} 
    4244 
     
    125127*/ 
    126128#identityUriBox { 
     129    font-size:0.9em; 
    127130    color: black; 
    128     background-color: #eef; 
     131    background-color: #e6f0f8; 
    129132    margin-top:20px;  
    130133    margin-bottom: 20px;  
    131134    padding-top: 10px;  
    132135    padding-right: 10px;  
    133     padding-left: 10px;  
    134     padding-bottom: 10px;  
     136    padding-left: 7px;  
     137    padding-bottom: 10px; 
    135138} 
    136139 
Note: See TracChangeset for help on using the changeset viewer.