Changeset 4155 for TI12-security


Ignore:
Timestamp:
01/09/08 11:39:28 (11 years ago)
Author:
pjkersha
Message:

Added and updated epydoc for openid_provider

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid_provider.py

    r4154 r4155  
    4242    
    4343class OpenIDProviderMiddleware(object): 
    44     """WSGI Middleware to implement an OpenID Provider""" 
     44    """WSGI Middleware to implement an OpenID Provider 
     45     
     46    @cvar defKw: keywords to __init__ and their default values.  Input 
     47    keywords must match these 
     48    @type defKw: dict 
     49     
     50    @cvar defPaths: subset of defKw.  These are keyword items corresponding 
     51    to the URL paths to be set for the individual OpenID Provider functions 
     52    @type: defPaths: dict 
     53     
     54    @cvar formRespWrapperTmpl: If the response to the Relying Party is too long 
     55    it's rendered as form with the POST method instead of query arguments in a  
     56    GET 302 redirect.  Wrap the form in this document to make the form submit  
     57    automatically without user intervention.  See _displayResponse method  
     58    below... 
     59    @type formRespWrapperTmpl: basestring""" 
     60     
     61    formRespWrapperTmpl = """<html> 
     62    <head> 
     63        <script type="text/javascript"> 
     64            function doRedirect() 
     65            { 
     66                document.forms[0].submit(); 
     67            } 
     68        </script> 
     69    </head> 
     70    <body onLoad="doRedirect()"> 
     71        %s 
     72    </body> 
     73</html>""" 
    4574 
    4675    defKw = dict(path_openidserver='/openidserver', 
     
    6695      
    6796    def __init__(self, app, app_conf=None, prefix='openid_provider.', **kw): 
    68         '''        
     97        ''' 
     98        @type app: callable following WSGI interface 
     99        @param app: next middleware application in the chain       
    69100        @type app_conf: dict         
    70101        @param app_conf: PasteDeploy application configuration dictionary 
     102        @type prefix: basestring 
     103        @param prefix: prefix for OpenID Provider configuration items 
     104        @type kw: dict 
     105        @param kw: keyword dictionary - must follow format of defKw  
     106        class variable     
    71107        ''' 
    72108 
     
    201237     
    202238    def __call__(self, environ, start_response): 
    203          
     239        """Standard WSGI interface.  Intercepts the path if it matches any of  
     240        the paths set in the path_* keyword settings to the config 
     241         
     242        @type environ: dict 
     243        @param environ: dictionary of environment variables 
     244        @type start_response: callable 
     245        @param start_response: standard WSGI callable to set HTTP headers 
     246        @rtype: basestring 
     247        @return: WSGI response 
     248        """ 
    204249        if not environ.has_key(self.session_middleware): 
    205250            raise OpenIDProviderConfigError('The session middleware %r is not ' 
     
    249294 
    250295    def do_id(self, environ, start_response): 
    251         '''Handle ID request''' 
     296        '''Handle ID request 
     297         
     298        @type environ: dict 
     299        @param environ: dictionary of environment variables 
     300        @type start_response: callable 
     301        @param start_response: standard WSGI callable to set HTTP headers 
     302        @rtype: basestring 
     303        @return: WSGI response 
     304        
     305        ''' 
    252306        response = self._renderer.renderIdentityPage(environ) 
    253307 
     
    259313 
    260314    def do_yadis(self, environ, start_response): 
    261         """Generate Yadis document""" 
     315        """Generate Yadis document 
     316         
     317        @type environ: dict 
     318        @param environ: dictionary of environment variables 
     319        @type start_response: callable 
     320        @param start_response: standard WSGI callable to set HTTP headers 
     321        @rtype: basestring 
     322        @return: WSGI response 
     323 
     324        """ 
    262325        response = self._renderer.renderYadis(environ) 
    263326      
     
    269332 
    270333    def do_openidserver(self, environ, start_response): 
    271         """Handle OpenID Server Request""" 
     334        """Handle OpenID Server Request 
     335         
     336        @type environ: dict 
     337        @param environ: dictionary of environment variables 
     338        @type start_response: callable 
     339        @param start_response: standard WSGI callable to set HTTP headers 
     340        @rtype: basestring 
     341        @return: WSGI response 
     342 
     343        """ 
    272344 
    273345        try: 
     
    294366    def do_allow(self, environ, start_response): 
    295367        """Handle allow request - user allow credentials to be passed back to 
    296         the Relying Party?""" 
     368        the Relying Party? 
     369         
     370        @type environ: dict 
     371        @param environ: dictionary of environment variables 
     372        @type start_response: callable 
     373        @param start_response: standard WSGI callable to set HTTP headers 
     374        @rtype: basestring 
     375        @return: WSGI response 
     376 
     377        """ 
    297378         
    298379        oidRequest = self.session.get('lastCheckIDRequest') 
     
    346427 
    347428    def do_serveryadis(self, environ, start_response): 
    348         """Handle Server Yadis call""" 
     429        """Handle Server Yadis call 
     430         
     431        @type environ: dict 
     432        @param environ: dictionary of environment variables 
     433        @type start_response: callable 
     434        @param start_response: standard WSGI callable to set HTTP headers 
     435        @rtype: basestring 
     436        @return: WSGI response 
     437 
     438        """ 
    349439        response = self._renderer.renderServerYadis(environ) 
    350440        start_response("200 OK",  
     
    355445 
    356446    def do_login(self, environ, start_response, **kw): 
    357         """Display Login form""" 
     447        """Display Login form 
     448         
     449        @type environ: dict 
     450        @param environ: dictionary of environment variables 
     451        @type start_response: callable 
     452        @param start_response: standard WSGI callable to set HTTP headers 
     453        @type kw: dict 
     454        @param kw: keywords to login renderer - see RenderingInterface class 
     455        @rtype: basestring 
     456        @return: WSGI response 
     457        """ 
    358458         
    359459        if 'fail_to' not in kw: 
     
    368468 
    369469    def do_loginsubmit(self, environ, start_response): 
    370         """Handle user submission from login and logout""" 
     470        """Handle user submission from login and logout 
     471         
     472        @type environ: dict 
     473        @param environ: dictionary of environment variables 
     474        @type start_response: callable 
     475        @param start_response: standard WSGI callable to set HTTP headers 
     476        @rtype: basestring 
     477        @return: WSGI response 
     478        """ 
    371479         
    372480        if 'submit' in self.query: 
     
    421529 
    422530    def do_mainpage(self, environ, start_response): 
    423  
     531        '''Show an information page about the OpenID Provider 
     532         
     533        @type environ: dict 
     534        @param environ: dictionary of environment variables 
     535        @type start_response: callable 
     536        @param start_response: standard WSGI callable to set HTTP headers 
     537        @rtype: basestring 
     538        @return: WSGI response 
     539        ''' 
     540         
    424541        response = self._renderer.renderMainPage(environ) 
    425542        start_response('200 OK',  
     
    431548    def do_decide(self, environ, start_response): 
    432549        """Display page prompting the user to decide whether to trust the site 
    433         requesting their credentials""" 
     550        requesting their credentials 
     551         
     552        @type environ: dict 
     553        @param environ: dictionary of environment variables 
     554        @type start_response: callable 
     555        @param start_response: standard WSGI callable to set HTTP headers 
     556        @rtype: basestring 
     557        @return: WSGI response 
     558        """ 
    434559 
    435560        oidRequest = self.session.get('lastCheckIDRequest') 
     
    454579         
    455580    def _identityIsAuthorized(self, oidRequest): 
    456         '''The given identity URL matches with a logged in user''' 
    457  
     581        '''Check that a user is authorized i.e. does a session exist for their 
     582        username and if so does it correspond to the identity URL provided. 
     583        This last check doesn't apply for ID Select mode where no ID was input 
     584        at the Relying Party. 
     585         
     586        @type oidRequest: openid.server.server.CheckIDRequest 
     587        @param oidRequest: OpenID Request object 
     588        @rtype: bool 
     589        @return: True/False is user authorized 
     590        ''' 
    458591        username = self.session.get('username') 
    459592        if username is None: 
     
    478611     
    479612    def _trustRootIsAuthorized(self, trust_root): 
    480         '''The given trust root (Relying Party) has previously been approved 
    481         by the user''' 
     613        '''Return True/False for the given trust root (Relying Party)  
     614        previously been approved by the user 
     615         
     616        @type trust_root: dict 
     617        @param trust_root: keyed by trusted root (Relying Party) URL and  
     618        containing string item 'always' if approved 
     619        @rtype: bool 
     620        @return: True - trust has already been approved, False - trust root is 
     621        not approved''' 
    482622        approvedRoots = self.session.get('approved', {}) 
    483623        return approvedRoots.get(trust_root) is not None 
    484624 
    485625 
    486     def _addSRegResponse(self, request, response): 
    487         '''Add Simple Registration attributes to response to Relying Party''' 
     626    def _addSRegResponse(self, oidRequest, oidResponse): 
     627        '''Add Simple Registration attributes to response to Relying Party 
     628         
     629        @type oidRequest: openid.server.server.CheckIDRequest 
     630        @param oidRequest: OpenID Check ID Request object 
     631        @type oidResponse: openid.server.server.OpenIDResponse 
     632        @param oidResponse: OpenID response object''' 
     633         
    488634        if self.sregResponseHandler is None: 
     635            # No Simple Registration response object was set 
    489636            return 
    490637         
    491         sreg_req = sreg.SRegRequest.fromOpenIDRequest(request) 
     638        sreg_req = sreg.SRegRequest.fromOpenIDRequest(oidRequest) 
    492639 
    493640        # Callout to external callable sets additional user attributes to be 
     
    495642        sreg_data = self.sregResponseHandler(self.session.get('username')) 
    496643        sreg_resp = sreg.SRegResponse.extractResponse(sreg_req, sreg_data) 
    497         response.addExtension(sreg_resp) 
    498  
    499  
    500     def _addAXResponse(self, request, response): 
     644        oidResponse.addExtension(sreg_resp) 
     645 
     646 
     647    def _addAXResponse(self, oidRequest, oidResponse): 
    501648        '''Add attributes to response based on the OpenID Attribute Exchange  
    502         interface''' 
    503  
    504         ax_req = ax.FetchRequest.fromOpenIDRequest(request) 
     649        interface 
     650         
     651        @type oidRequest: openid.server.server.CheckIDRequest 
     652        @param oidRequest: OpenID Check ID Request object 
     653        @type oidResponse: openid.server.server.OpenIDResponse 
     654        @param oidResponse: OpenID response object''' 
     655 
     656 
     657        ax_req = ax.FetchRequest.fromOpenIDRequest(oidRequest) 
    505658        if ax_req is None: 
    506659            log.debug("No Attribute Exchange extension set in request") 
     
    520673        # release of attributes + assignment based on required attributes -  
    521674        # possibly via FetchRequest.getRequiredAttrs() 
    522 #        for typeURI, attrInfo in ax_req.requested_attributes.items(): 
    523 #            # Value input must be list type 
    524 #            ax_resp.setValues(typeURI, [attrInfo.alias+"Value"]) 
    525675        self.axResponseHandler(ax_req, ax_resp, self.session.get('username')) 
    526676         
    527         response.addExtension(ax_resp) 
    528          
    529          
    530     def _identityApproved(self, request, identifier=None): 
    531         '''Action following approval of a Relying Party by the user''' 
    532         response = request.answer(True, identity=identifier) 
    533         self._addSRegResponse(request, response) 
    534         self._addAXResponse(request, response) 
    535         return response 
     677        oidResponse.addExtension(ax_resp) 
     678         
     679         
     680    def _identityApproved(self, oidRequest, identifier=None): 
     681        '''Action following approval of a Relying Party by the user.  Add 
     682        Simple Registration and/or Attribute Exchange parameters if handlers 
     683        were specified - See _addSRegResponse and _addAXResponse methods 
     684         
     685        @type oidRequest: openid.server.server.CheckIDRequest 
     686        @param oidRequest: OpenID Check ID Request object 
     687        @type identifier: basestring 
     688        @param identifier: OpenID selected by user - for ID Select mode only 
     689        @rtype oidResponse: openid.server.server.OpenIDResponse 
     690        @return oidResponse: OpenID response object''' 
     691 
     692        oidResponse = oidRequest.answer(True, identity=identifier) 
     693        self._addSRegResponse(oidRequest, oidResponse) 
     694        self._addAXResponse(oidRequest, oidResponse) 
     695         
     696        return oidResponse 
    536697 
    537698 
    538699    def _handleCheckIDRequest(self, oidRequest): 
    539          
     700        """Handle "checkid_immediate" and "checkid_setup" type requests from 
     701        Relying Party 
     702         
     703        @type oidRequest: openid.server.server.CheckIDRequest 
     704        @param oidRequest: OpenID Check ID request 
     705        @rtype: basestring 
     706        @return: WSGI response 
     707        """ 
    540708        log.debug("OpenIDProviderMiddleware._handleCheckIDRequest ...") 
    541709         
     
    575743            return response 
    576744 
    577     # If the response to the Relying Party is too long it's rendered as form 
    578     # with the POST method instead of query arguments in a GET 302 redirect. 
    579     # Wrap the form in this document to make the form submit automatically 
    580     # without user intervention.  See _displayResponse method below... 
    581     formRespWrapperTmpl = """<html> 
    582     <head> 
    583         <script type="text/javascript"> 
    584             function doRedirect() 
    585             { 
    586                 document.forms[0].submit(); 
    587             } 
    588         </script> 
    589     </head> 
    590     <body onLoad="doRedirect()"> 
    591         %s 
    592     </body> 
    593 </html>""" 
    594745 
    595746    def _displayResponse(self, oidResponse): 
     747        """Serialize an OpenID Response object, set headers and return WSGI 
     748        response. 
     749         
     750        If the URL length for a GET request exceeds a maximum, then convert the 
     751        response into a HTML form and use POST method. 
     752         
     753        @type oidResponse: openid.server.server.OpenIDResponse 
     754        @param oidResponse: OpenID response object 
     755         
     756        @rtype: basestring 
     757        @return: WSGI response''' 
     758        """ 
     759         
    596760        try: 
    597761            webresponse = self.oidserver.encodeResponse(oidResponse) 
     
    622786 
    623787    def _redirect(self, start_response, url): 
     788        """Do a HTTP 302 redirect 
     789         
     790        @type start_response: callable following WSGI start_response convention 
     791        @param start_response: WSGI start response callable 
     792        @type url: basestring 
     793        @param url: URL to redirect to 
     794        @rtype: list 
     795        @return: empty HTML body 
     796        """ 
    624797        start_response('302 %s' % httplib.responses[302],  
    625798                       [('Content-type', 'text/html'+self.charset), 
     
    629802 
    630803    def _showErrorPage(self, msg, code=500): 
     804        """Display error information to the user 
     805         
     806        @type msg: basestring 
     807        @param msg: error message 
     808        @type code: int 
     809        @param code: HTTP error code 
     810        """ 
     811         
    631812        response = self._renderer.renderErrorPage(self.environ,cgi.escape(msg)) 
    632813        self.start_response('%d %s' % (code, httplib.responses[code]),  
     
    640821    derivative from this class to override the default look and feel and  
    641822    behaviour of these pages.  Pass the new class name via the renderClass 
    642     keyword to OpenIDProviderMiddleware.__init__""" 
    643      
     823    keyword to OpenIDProviderMiddleware.__init__ 
     824     
     825    @cvar tmplServerYadis: template for returning Yadis document to Relying  
     826    Party.  Derived classes can reset this or completely override the  
     827    renderServerYadis method. 
     828     
     829    @type tmplServerYadis: basestring 
     830     
     831    @cvar tmplYadis: template for returning Yadis document containing user 
     832    URL to Relying Party.  Derived classes can reset this or completely  
     833    override the renderYadis method. 
     834     
     835    @type tmplYadis: basestring""" 
     836    
     837    tmplServerYadis = """\ 
     838<?xml version="1.0" encoding="UTF-8"?> 
     839<xrds:XRDS 
     840    xmlns:xrds="xri://$xrds" 
     841    xmlns="xri://$xrd*($v*2.0)"> 
     842  <XRD> 
     843 
     844    <Service priority="0"> 
     845      <Type>%(openid20type)s</Type> 
     846      <URI>%(endpoint_url)s</URI> 
     847    </Service> 
     848 
     849  </XRD> 
     850</xrds:XRDS> 
     851""" 
     852 
     853    tmplYadis = """\ 
     854<?xml version="1.0" encoding="UTF-8"?> 
     855<xrds:XRDS 
     856    xmlns:xrds="xri://$xrds" 
     857    xmlns="xri://$xrd*($v*2.0)"> 
     858  <XRD> 
     859 
     860    <Service priority="0"> 
     861      <Type>%(openid20type)s</Type> 
     862      <Type>%(openid10type)s</Type> 
     863      <URI>%(endpoint_url)s</URI> 
     864      <LocalID>%(user_url)s</LocalID> 
     865    </Service> 
     866 
     867  </XRD> 
     868</xrds:XRDS>"""     
     869    
    644870    def __init__(self, base_url, urls): 
     871        """ 
     872        @type base_url: basestring 
     873        @param base_url: base URL for OpenID Provider to which individual paths 
     874        are appended 
     875        @type urls: dict 
     876        @param urls: full urls for all the paths used by all the exposed  
     877        methods - keyed by method name - see OpenIDProviderMiddleware.paths 
     878        """ 
    645879        self.base_url = base_url 
    646880        self.urls = urls 
    647881 
     882 
    648883    def renderIdentityPage(self, environ): 
    649         """Render the identity page.""" 
     884        """Render the identity page. 
     885         
     886        @type environ: dict 
     887        @param environ: dictionary of environment variables 
     888        @rtype: basestring 
     889        @return: WSGI response 
     890        """ 
    650891        path = environ.get('PATH_INFO').rstrip('/') 
    651892        username = path[len(self.paths['path_id'])+1:] 
     
    654895              self.urls['url_openidserver'] 
    655896               
    656         yadis_loc_tag = '<meta http-equiv="x-xrds-location" content="%s">'%\ 
     897        yadis_loc_tag = '<meta http-equiv="x-xrds-location" content="%s">' % \ 
    657898            (self.urls['url_yadis']+'/'+path[4:]) 
    658899             
     
    668909                                ''' % (ident, msg)) 
    669910     
    670     tmplServerYadis = """\ 
    671 <?xml version="1.0" encoding="UTF-8"?> 
    672 <xrds:XRDS 
    673     xmlns:xrds="xri://$xrds" 
    674     xmlns="xri://$xrd*($v*2.0)"> 
    675   <XRD> 
    676  
    677     <Service priority="0"> 
    678       <Type>%(openid20type)s</Type> 
    679       <URI>%(endpoint_url)s</URI> 
    680     </Service> 
    681  
    682   </XRD> 
    683 </xrds:XRDS> 
    684 """ 
    685  
     911     
    686912    def renderServerYadis(self, environ): 
    687         '''Render Yadis info''' 
     913        '''Render Yadis info 
     914         
     915        @type environ: dict 
     916        @param environ: dictionary of environment variables 
     917        @rtype: basestring 
     918        @return: WSGI response 
     919        ''' 
    688920        endpoint_url = self.urls['url_openidserver'] 
    689921        return RenderingInterface.tmplServerYadis % \ 
    690922            {'openid20type': discover.OPENID_IDP_2_0_TYPE,  
    691              'endpoint_url': endpoint_url} 
    692          
    693     tmplYadis = """\ 
    694 <?xml version="1.0" encoding="UTF-8"?> 
    695 <xrds:XRDS 
    696     xmlns:xrds="xri://$xrds" 
    697     xmlns="xri://$xrd*($v*2.0)"> 
    698   <XRD> 
    699  
    700     <Service priority="0"> 
    701       <Type>%(openid20type)s</Type> 
    702       <Type>%(openid10type)s</Type> 
    703       <URI>%(endpoint_url)s</URI> 
    704       <LocalID>%(user_url)s</LocalID> 
    705     </Service> 
    706  
    707   </XRD> 
    708 </xrds:XRDS>"""     
    709      
    710      
     923             'endpoint_url': endpoint_url}     
     924 
     925 
    711926    def renderYadis(self, environ): 
    712         """Render Yadis document""" 
     927        """Render Yadis document containing user URL 
     928         
     929        @type environ: dict 
     930        @param environ: dictionary of environment variables 
     931        @rtype: basestring 
     932        @return: WSGI response 
     933        """ 
     934         
    713935        username = environ['PATH_INFO'].rstrip('/').split('/')[-1] 
    714936         
     
    725947         
    726948    def renderLogin(self, environ, success_to=None, fail_to=None, msg=''): 
    727         """Render the login form.""" 
     949        """Render the login form. 
     950         
     951        @type environ: dict 
     952        @param environ: dictionary of environment variables 
     953        @type success_to: basestring 
     954        @param success_to: URL put into hidden field telling   
     955        OpenIDProviderMiddleware.do_loginsubmit() where to forward to on  
     956        successful login 
     957        @type fail_to: basestring 
     958        @param fail_to: URL put into hidden field telling   
     959        OpenIDProviderMiddleware.do_loginsubmit() where to forward to on  
     960        login error 
     961        @type msg: basestring 
     962        @param msg: display (error) message below login form e.g. following 
     963        previous failed login attempt. 
     964        @rtype: basestring 
     965        @return: WSGI response 
     966        """ 
    728967         
    729968        if success_to is None: 
     
    748987 
    749988    def renderMainPage(self, environ): 
    750         """Rendering the main page.""" 
     989        """Rendering the main page. 
     990         
     991        @type environ: dict 
     992        @param environ: dictionary of environment variables 
     993        @rtype: basestring 
     994        @return: WSGI response 
     995        """ 
    751996         
    752997        yadis_tag = '<meta http-equiv="x-xrds-location" content="%s">' % \ 
     
    7741019     
    7751020    def renderDecidePage(self, environ, oidRequest): 
     1021        """Show page giving the user the option to approve the return of their 
     1022        credentials to the Relying Party.  This page is also displayed for 
     1023        ID select mode if the user is already logged in at the OpenID Provider. 
     1024        This enables them to confirm the OpenID to be sent back to the  
     1025        Relying Party 
     1026         
     1027        @type environ: dict 
     1028        @param environ: dictionary of environment variables 
     1029        @type oidRequest: openid.server.server.CheckIDRequest 
     1030        @param oidRequest: OpenID Check ID Request object 
     1031        @rtype: basestring 
     1032        @return: WSGI response 
     1033        """ 
    7761034        id_url_base = self.urls['url_id'] + '/' 
    7771035         
     
    8861144    def _showPage(self, environ,  
    8871145                  title, head_extras='', msg=None, err=None, form=None): 
    888  
     1146        """Generic page rendering method.  Derived classes may ignore this. 
     1147         
     1148        @type environ: dict 
     1149        @param environ: dictionary of environment variables 
     1150        @type title: basestring 
     1151        @param title: page title 
     1152        @type head_extras: basestring 
     1153        @param head_extras: add extra HTML header elements 
     1154        @type msg: basestring 
     1155        @param msg: optional message for page body 
     1156        @type err: basestring 
     1157        @param err: optional error message for page body 
     1158        @type form: basestring 
     1159        @param form: optional form for page body         
     1160        @rtype: basestring 
     1161        @return: WSGI response 
     1162        """ 
     1163         
    8891164        username = environ['beaker.session'].get('username') 
    8901165        if username is None: 
     
    10081283 
    10091284    def renderErrorPage(self, environ, msg): 
     1285        """Display error page  
     1286         
     1287        @type environ: dict 
     1288        @param environ: dictionary of environment variables 
     1289        @type msg: basestring 
     1290        @param msg: optional message for page body 
     1291        @rtype: basestring 
     1292        @return: WSGI response 
     1293        """ 
     1294         
    10101295        response = self._showPage(environ, 'Error Processing Request', err='''\ 
    10111296        <p>%s</p> 
Note: See TracChangeset for help on using the changeset viewer.