Ignore:
Timestamp:
11/01/10 09:29:41 (10 years ago)
Author:
pjkersha
Message:
  • ndg.security.server.wsgi.NDGSecurityMiddlewareBase: change code to leave trailing space in path info attribute
  • ndg.security.server.wsgi.openid.provider.OpenIDProviderMiddleware:
    • added properties with type checking
    • added trustedRelyingParties attribute - a list of sites trusted by the Provider for which no decide page interface is invoked.
  • ndg.security.server.wsgi.openid.provider.axinterface.csv: fixed adding of AX attributes for CSV class. Required attributes were being set twice.
  • ndg.security.server.wsgi.openid.relyingparty.OpenIDRelyingParty:
    • changed whitelisting to use ndg.security.server.wsgi.openid.relyingparty.validation.SSLIdPValidationDriver class. FIXME: Fix required in SSL verify callback needed to check only the server certificate in the verification chain and ignore CA certificates.
  • ndg.security.server.wsgi.openid.relyingparty.validation.SSLIdPValidationDriver: changed to init to include keyword option for installing default urllib2 opener and defaulting to OMIT it.
Location:
TI12-security/trunk/NDGSecurity/python
Files:
2 added
15 edited

Legend:

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

    • Property svn:ignore set to
      *.egg-info
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/__init__.py

    r6069 r6276  
    255255                raise AttributeError("SCRIPT_URL key not set in environ: " 
    256256                                     "'mountPath' is set to None") 
    257              
    258         if self._mountPath != '/': 
    259             self._mountPath = self._mountPath.rstrip('/') 
     257         
     258        # Comment out as it breaks standard for URL trailing slash  
     259#        if self._mountPath != '/': 
     260#            self._mountPath = self._mountPath.rstrip('/') 
    260261         
    261262    def _getMountPath(self): 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/__init__.py

    r6246 r6276  
    2424import paste.request 
    2525from paste.util.import_string import eval_import 
     26import beaker.session 
    2627from openid.extensions import sreg, ax 
    2728from openid.server import server 
     
    163164        trace=False, 
    164165        renderingClass=None, 
    165         sregResponseHandler=None, 
    166         axResponseHandler=None, 
    167         authNInterface=AbstractAuthNInterface) 
     166        sregResponse=None, 
     167        axResponse=None, 
     168        authNInterface=AbstractAuthNInterface, 
     169        trustedRelyingParties=()) 
    168170     
    169171    defPaths = dict([(k, v) for k, v in defOpt.items()  
     
    184186    APPROVE_RP_SUBMIT = "ApproveRelyingParty" 
    185187    REJECT_RP_SUBMIT = "RejectRelyingParty" 
     188     
     189    TRUSTED_RELYINGPARTIES_SEP_PAT = re.compile(',\s*') 
    186190     
    187191    def __init__(self, app, app_conf=None, prefix=PARAM_PREFIX, **kw): 
     
    197201        class variable     
    198202        ''' 
    199         self._app = app 
    200         self._environ = {} 
    201         self._start_response = None 
    202         self._pathInfo = None 
    203         self._path = None 
    204         self.mountPath = '/' 
     203        super(OpenIDProviderMiddleware, self).__init__(app, {}) 
     204#        self._app = app 
     205#        self._environ = {} 
     206#        self._start_response = None 
     207#        self._pathInfo = None 
     208#        self._path = None 
     209#        self.mountPath = '/' 
     210         
     211        self.__charset = None 
     212        self.__paths = None 
     213        self.__base_url = None 
     214        self.__urls = None 
     215        self.__method = None 
     216        self.__sessionMiddlewareEnvironKeyName = None 
     217        self.__session = None   
     218        self.__oidserver = None 
     219        self.__query = {} 
     220        self.__sregResponse = None 
     221        self.__trustedRelyingParties = () 
     222        self.__axResponse = None 
    205223         
    206224        # See _createResponse method 
    207         self.oidResponse = None 
     225        self.__oidResponse = None 
    208226 
    209227        opt = OpenIDProviderMiddleware.defOpt.copy() 
     
    220238        opt.update(kw) 
    221239         
    222         # Convert from string type where required    
    223         opt['charset'] = opt.get('charset', '') 
    224         opt['trace'] = opt.get('trace', 'false').lower() == 'true' 
     240        self.charset = opt['charset'] 
     241       
     242        # If True and debug log level is set display content of response 
     243        self._trace = opt.get('trace', 'false').lower() == 'true' 
    225244          
    226245        renderingClassVal = opt.get('renderingClass', None)       
     
    228247            opt['renderingClass'] = eval_import(renderingClassVal) 
    229248         
    230         sregResponseHandlerVal = opt.get('sregResponseHandler', None)   
    231         if sregResponseHandlerVal: 
    232             opt['sregResponseHandler'] = eval_import(sregResponseHandlerVal)   
     249        sregResponseVal = opt.get('sregResponse', None)   
     250        if sregResponseVal: 
     251            opt['sregResponse'] = eval_import(sregResponseVal)   
    233252        else: 
    234             opt['sregResponseHandler'] = None 
    235  
    236         axResponseHandlerVal = opt.get('axResponseHandler', None)   
    237         if axResponseHandlerVal: 
    238             opt['axResponseHandler'] = eval_import(axResponseHandlerVal) 
    239         else: 
    240             opt['axResponseHandler'] = None 
     253            opt['sregResponse'] = None 
    241254 
    242255        # Authentication interface to OpenID Provider - interface to for  
     
    288301                            for k, v in self.paths.items()]) 
    289302 
    290         self.session_middleware = opt['session_middleware'] 
    291  
    292         if not opt['charset']: 
    293             self.charset = '' 
    294         else: 
    295             self.charset = '; charset=' + charset 
    296          
    297         # If True and debug log level is set display content of response 
    298         self._trace = opt['trace'] 
     303        self.sessionMiddlewareEnvironKeyName = opt['session_middleware'] 
    299304 
    300305        log.debug("opt=%r", opt)         
     
    326331        # Callable for setting of Simple Registration attributes in HTTP header 
    327332        # of response to Relying Party 
    328         self.sregResponseHandler = opt.get('sregResponseHandler', None) 
    329         if self.sregResponseHandler and not callable(self.sregResponseHandler): 
     333        self.sregResponse = opt.get('sregResponse', None) 
     334        if self.sregResponse and not callable(self.sregResponse): 
    330335            raise OpenIDProviderMiddlewareError("Expecting callable for " 
    331                                                 "sregResponseHandler keyword, " 
     336                                                "sregResponse keyword, " 
    332337                                                "got %r" %  
    333                                                 self.sregResponseHandler) 
     338                                                self.sregResponse) 
    334339             
    335340        # Class to handle OpenID Attribute Exchange (AX) requests from 
    336341        # the Relying Party 
    337342        axResponseClassName = opt.pop('axResponse_class', None) 
    338         if axResponseClassName is None: 
    339             # No AX Response handler set 
    340             self.axResponse = None 
    341         else: 
     343        if axResponseClassName is not None: 
    342344            axResponseModuleFilePath = opt.pop('axResponse_moduleFilePath', 
    343345                                               None) 
     
    347349                
    348350            try: 
    349                 self.axResponse = instantiateClass( 
    350                                     axResponseClassName,  
    351                                     None,  
    352                                     moduleFilePath=axResponseModuleFilePath, 
    353                                     objectType=AXInterface,  
    354                                     classProperties=axResponseProperties) 
     351                self.__axResponse = instantiateClass( 
     352                                        axResponseClassName,  
     353                                        None,  
     354                                        moduleFilePath=axResponseModuleFilePath, 
     355                                        objectType=AXInterface,  
     356                                        classProperties=axResponseProperties) 
    355357            except Exception, e: 
    356358                log.error("Error instantiating AX interface: %s" % e) 
    357359                raise 
    358          
     360     
     361        self.trustedRelyingParties = opt['trustedRelyingParties'] 
     362             
    359363        # Instantiate OpenID consumer store and OpenID consumer.  If you 
    360364        # were connecting to a database, you would create the database 
     
    363367                            os.path.expandvars(opt['consumer_store_dirpath'])) 
    364368        self.oidserver = server.Server(store, self.urls['url_openidserver']) 
     369 
     370    def getCharset(self): 
     371        return self.__charset 
     372 
     373    def getPaths(self): 
     374        return self.__paths 
     375 
     376    def getBase_url(self): 
     377        return self.__base_url 
     378 
     379    def getUrls(self): 
     380        return self.__urls 
     381 
     382    def getMethod(self): 
     383        return self.__method 
     384 
     385    def getSessionMiddlewareEnvironKeyName(self): 
     386        return self.__sessionMiddlewareEnvironKeyName 
     387 
     388    def getSession(self): 
     389        return self.__session 
     390 
     391    def setCharset(self, value):         
     392        # Convert from string type where required    
     393        if not value: 
     394            self.__charset = '' 
     395        elif isinstance(value, basestring): 
     396            self.__charset = '; charset=' + value 
     397        else: 
     398            raise TypeError('Expecting string type for "charset" attribute; ' 
     399                            'got %r' % type(value)) 
     400 
     401    def setPaths(self, value): 
     402        if not isinstance(value, dict): 
     403            raise TypeError('Expecting dict type for ' 
     404                            '"paths" attribute; got %r' % 
     405                            type(value)) 
     406        self.__paths = value 
     407 
     408    def setBase_url(self, value): 
     409        if not isinstance(value, basestring): 
     410            raise TypeError('Expecting string type for ' 
     411                            '"base_url" attribute; got %r' % 
     412                            type(value)) 
     413        self.__base_url = value 
     414 
     415    def setUrls(self, value): 
     416        if not isinstance(value, dict): 
     417            raise TypeError('Expecting dict type for ' 
     418                            '"urls" attribute; got %r' % 
     419                            type(value)) 
     420        self.__urls = value 
     421 
     422    def setMethod(self, value): 
     423        if not isinstance(value, dict): 
     424            raise TypeError('Expecting dict type for ' 
     425                            '"method" attribute; got %r' % 
     426                            type(value)) 
     427        self.__method = value 
     428 
     429    def setSessionMiddlewareEnvironKeyName(self, value): 
     430        if not isinstance(value, basestring): 
     431            raise TypeError('Expecting string type for ' 
     432                            '"sessionMiddlewareEnvironKeyName" attribute; ' 
     433                            'got %r' % 
     434                            type(value)) 
     435        self.__sessionMiddlewareEnvironKeyName = value 
     436 
     437    def setSession(self, value): 
     438        if not isinstance(value, beaker.session.SessionObject): 
     439            raise TypeError('Expecting beaker.session.SessionObject type for ' 
     440                            '"session" attribute; got %r' % 
     441                            type(value)) 
     442 
     443        self.__session = value 
     444 
     445    def getOidResponse(self): 
     446        return self.__oidResponse 
     447 
     448    def getSregResponse(self): 
     449        return self.__sregResponse 
     450 
     451    def getAxResponse(self): 
     452        return self.__axResponse 
     453 
     454    def getOidserver(self): 
     455        return self.__oidserver 
     456 
     457    def getQuery(self): 
     458        return self.__query 
     459 
     460    def getTrustedRelyingParties(self): 
     461        return self.__trustedRelyingParties 
     462 
     463    def setOidResponse(self, value): 
     464        if not isinstance(value, server.OpenIDResponse): 
     465            raise TypeError('Expecting OpenIDResponse type for ' 
     466                            '"oidResponse" attribute; got %r' % 
     467                            type(value)) 
     468        self.__oidResponse = value 
     469 
     470    def setSregResponse(self, value): 
     471        self.__sregResponse = value 
     472 
     473    def setAxResponse(self, value): 
     474        if not isinstance(value, AXInterface): 
     475            raise TypeError('Expecting AXInterface type for ' 
     476                            '"axResponse" attribute; got %r' % 
     477                            type(value)) 
     478        self.__axResponse = value 
     479 
     480    def setOidserver(self, value): 
     481        if not isinstance(value, server.Server): 
     482            raise TypeError('Expecting openid.server.server.Server type for ' 
     483                            '"oidserver" attribute; got %r' % 
     484                            type(value)) 
     485        self.__oidserver = value 
     486 
     487    def setQuery(self, value): 
     488        if not isinstance(value, dict): 
     489            raise TypeError('Expecting dict type for ' 
     490                            '"query" attribute; got %r' % 
     491                            type(value)) 
     492        self.__query = value 
     493 
     494    def setTrustedRelyingParties(self, value): 
     495        if isinstance(value, basestring): 
     496            pat = OpenIDProviderMiddleware.TRUSTED_RELYINGPARTIES_SEP_PAT 
     497            self.__trustedRelyingParties = tuple([i for i in pat.split(value)]) 
     498             
     499        elif isinstance(value, (list, tuple)): 
     500            self.__trustedRelyingParties = tuple(value) 
     501        else: 
     502            raise TypeError('Expecting list or tuple type for ' 
     503                            '"trustedRelyingParties" attribute; got %r' % 
     504                            type(value)) 
    365505         
    366506    @classmethod 
     
    504644        @return: WSGI response 
    505645        """ 
    506         if not environ.has_key(self.session_middleware): 
     646        if not environ.has_key(self.sessionMiddlewareEnvironKeyName): 
    507647            raise OpenIDProviderConfigError('The session middleware %r is not ' 
    508648                                            'present. Have you set up the ' 
    509649                                            'session middleware?' % 
    510                                             self.session_middleware) 
     650                                        self.sessionMiddlewareEnvironKeyName) 
    511651 
    512652        # Beware path is a property and invokes the _setPath method 
    513         self.session = environ[self.session_middleware] 
     653        self.session = environ[self.sessionMiddlewareEnvironKeyName] 
    514654        self._render.session = self.session 
    515655         
     
    9831123        except (OpenIDProviderMissingRequiredAXAttrs, 
    9841124                OpenIDProviderMissingAXResponseHandler): 
     1125            log.error("%s type exception raised setting response following ID " 
     1126                      "Approval: %s", e.__class__.__name__,  
     1127                      traceback.format_exc()) 
    9851128            response = self._render.errorPage(self.environ,  
    9861129                                              self.start_response, 
     
    9921135             
    9931136        except OpenIDProviderReloginRequired, e: 
     1137            log.error("%s type exception raised setting response following ID " 
     1138                      "Approval: %s", e.__class__.__name__,  
     1139                      traceback.format_exc()) 
    9941140            response = self._render.errorPage(self.environ,  
    9951141                                              self.start_response, 
     
    10261172            return response 
    10271173 
    1028     def _identityIsAuthorized(self, oidRequest): 
     1174    def _identityIsAuthenticated(self, oidRequest): 
    10291175        '''Check that a user is authorized i.e. does a session exist for their 
    10301176        username and if so does it correspond to the identity URL provided. 
     
    10431189 
    10441190        if oidRequest.idSelect(): 
    1045             log.debug("OpenIDProviderMiddleware._identityIsAuthorized - " 
     1191            log.debug("OpenIDProviderMiddleware._identityIsAuthenticated - " 
    10461192                      "ID Select mode set but user is already logged in") 
    10471193            return True 
     
    10531199         
    10541200        if oidRequest.identity != identityURI: 
    1055             log.debug("OpenIDProviderMiddleware._identityIsAuthorized - user " 
     1201            log.debug("OpenIDProviderMiddleware._identityIsAuthenticated - user " 
    10561202                      "is already logged in with a different ID=%s and " 
    10571203                      "identityURI=%s" % 
     
    10591205            return False 
    10601206         
    1061         log.debug("OpenIDProviderMiddleware._identityIsAuthorized - " 
     1207        log.debug("OpenIDProviderMiddleware._identityIsAuthenticated - " 
    10621208                  "user is logged in with ID matching ID URI") 
    10631209        return True 
     
    10791225        return approvedRoots.get(trust_root) is not None 
    10801226 
     1227    def _isConfiguredTrustedRoot(self, trust_root): 
     1228        """the Relying Party is one of a 
     1229        list of RPs set in the start up configuration as not needing 
     1230        approval.  This could be for example sites within the same 
     1231        organisation as this Provider 
     1232 
     1233        @type trust_root: dict 
     1234        @param trust_root: keyed by trusted root (Relying Party) URL and  
     1235        containing string item 'always' if approved 
     1236        @rtype: bool 
     1237        @return: True - trust has already been approved, False - trust root is 
     1238        not approved 
     1239        """ 
     1240        return trust_root in self.trustedRelyingParties 
     1241     
    10811242    def _addSRegResponse(self, oidRequest): 
    10821243        '''Add Simple Registration attributes to response to Relying Party 
     
    10851246        @param oidRequest: OpenID Check ID Request object''' 
    10861247         
    1087         if self.sregResponseHandler is None: 
     1248        if self.sregResponse is None: 
    10881249            # No Simple Registration response object was set 
    10891250            return 
     
    10931254        # Callout to external callable sets additional user attributes to be 
    10941255        # returned in response to Relying Party         
    1095         sreg_data = self.sregResponseHandler(self.session.get( 
     1256        sreg_data = self.sregResponse(self.session.get( 
    10961257                            OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME)) 
    10971258        sreg_resp = sreg.SRegResponse.extractResponse(sreg_req, sreg_data) 
     
    11171278            if len(requiredAttr) > 0: 
    11181279                msg = ("Relying party requires these attributes: %s; but No" 
    1119                        "Attribute exchange handler 'axResponseHandler' has " 
     1280                       "Attribute exchange handler 'axResponse' has " 
    11201281                       "been set" % requiredAttr) 
    11211282                log.error(msg) 
     
    11861347        self.session.save() 
    11871348         
    1188         if self._identityIsAuthorized(oidRequest): 
     1349        if self._identityIsAuthenticated(oidRequest): 
    11891350             
    11901351            # User is logged in - check for ID Select type request i.e. the 
     
    11921353            # full OpenID URL.  In this case, the identity they wish to use must 
    11931354            # be confirmed. 
    1194             if oidRequest.idSelect(): 
     1355            isConfiguredTrustedRoot = self._isConfiguredTrustedRoot( 
     1356                                                        oidRequest.trust_root) 
     1357            if oidRequest.idSelect() and not isConfiguredTrustedRoot: 
    11951358                # OpenID identifier must be confirmed 
    11961359                return self.do_decide(self.environ, self.start_response) 
    11971360             
    1198             elif self._trustRootIsAuthorized(oidRequest.trust_root): 
     1361            elif (self._trustRootIsAuthorized(oidRequest.trust_root) or 
     1362                  isConfiguredTrustedRoot): 
     1363                 
    11991364                # User entered their full OpenID URL and they have previously  
    1200                 # approved this Relying Party 
     1365                # approved this Relying Party OR the Relying Party is one of a 
     1366                # list of RPs set in the start up configuration as not needing 
     1367                # approval.  This could be for example sites within the same 
     1368                # organisation as this Provider 
    12011369                try: 
    1202                     self._createResponse(oidRequest) 
     1370                    identityURI = self.session[ 
     1371                        OpenIDProviderMiddleware.IDENTITY_URI_SESSION_KEYNAME 
     1372                    ] 
     1373                    self._createResponse(oidRequest, identifier=identityURI) 
    12031374                     
    12041375                except (OpenIDProviderMissingRequiredAXAttrs, 
     
    13111482        return [] 
    13121483 
     1484    charset = property(getCharset, setCharset, None, "Charset's Docstring") 
     1485 
     1486    paths = property(getPaths, setPaths, None, "Dictionary of Paths for the app") 
     1487 
     1488    base_url = property(getBase_url, setBase_url, None, "Base URL for the app") 
     1489 
     1490    urls = property(getUrls, setUrls, None, "dictionary of URLs for app") 
     1491 
     1492    method = property(getMethod, setMethod, None,  
     1493                      "Method name keyed from requested URL") 
     1494 
     1495    sessionMiddlewareEnvironKeyName = property( 
     1496                                  getSessionMiddlewareEnvironKeyName,  
     1497                                  setSessionMiddlewareEnvironKeyName,  
     1498                                  None,  
     1499                                  "environ key name for Beaker Session " 
     1500                                  "middleware") 
     1501 
     1502    session = property(getSession, setSession, None, "Session's Docstring") 
     1503 
     1504    oidResponse = property(getOidResponse,  
     1505                           setOidResponse,  
     1506                           None,  
     1507                           "OpenID response object") 
     1508 
     1509    sregResponse = property(getSregResponse,  
     1510                            setSregResponse,  
     1511                            None,  
     1512                            "SReg response handler class") 
     1513 
     1514    axResponse = property(getAxResponse, setAxResponse, None,  
     1515                          "Attribute Exchange response object") 
     1516 
     1517    oidserver = property(getOidserver, setOidserver, None,  
     1518                         "OpenID server instance") 
     1519 
     1520    query = property(getQuery, setQuery, None,  
     1521                     "dictionary of HTML query parameters") 
     1522 
     1523    trustedRelyingParties = property(getTrustedRelyingParties,  
     1524                                     setTrustedRelyingParties,  
     1525                                     None,  
     1526                                     "Relying Parties trusted by this Provider") 
     1527 
    13131528     
    13141529class RenderingInterfaceError(Exception): 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/axinterface/__init__.py

    r6069 r6276  
    3838    def __init__(self, **cfg): 
    3939        """Add custom settings from the OpenID Provider's  
    40         openid.provider.axResponseHandler.* settings contained in the host  
     40        openid.provider.axResponse.* settings contained in the host  
    4141        Paste ini file 
    4242         
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/axinterface/csv.py

    r6069 r6276  
    167167                                       ', '.join(missingAttributeURIs)) 
    168168         
    169         # Add the required attributes 
    170         for requiredAttributeURI in requiredAttributeURIs: 
    171             log.info("Adding required AX parameter %s=%s ...",  
    172                      requiredAttributeURI, 
    173                      userAttributeMap[requiredAttributeURI]) 
    174              
    175             ax_resp.addValue(requiredAttributeURI, 
    176                              userAttributeMap[requiredAttributeURI]) 
    177              
    178         # Append requested attribute if available 
     169        # Add the requested attributes 
    179170        for requestedAttributeURI in ax_req.requested_attributes.keys(): 
    180171            if requestedAttributeURI in self.attributeNames: 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/relyingparty/__init__.py

    r6069 r6276  
    1616import httplib # to get official status code messages 
    1717import urllib # decode quoted URI in query arg 
     18import urllib2 # SSL based whitelisting  
    1819from urlparse import urlsplit, urlunsplit 
    19  
    2020 
    2121from paste.request import parse_querystring, parse_formvars 
     
    2424from beaker.middleware import SessionMiddleware 
    2525 
     26# SSL based whitelisting  
     27from M2Crypto import SSL 
     28from M2Crypto.m2urllib2 import build_opener, HTTPSHandler 
     29from openid.fetchers import setDefaultFetcher, Urllib2Fetcher 
     30 
     31from ndg.security.common.utils.classfactory import instantiateClass 
    2632from ndg.security.server.wsgi import NDGSecurityMiddlewareBase 
    2733from ndg.security.server.wsgi.authn import AuthnRedirectMiddleware 
    28 from ndg.security.common.utils.classfactory import instantiateClass 
     34from ndg.security.server.wsgi.openid.relyingparty.validation import ( 
     35                                                        SSLIdPValidationDriver) 
    2936 
    3037 
     
    4855    ''' 
    4956    sslPropertyDefaults = { 
    50         'certFilePath': '', 
    51         'priKeyFilePath': None, 
    52         'priKeyPwd': None, 
    53         'caCertDirPath': None, 
    54         'providerWhitelistFilePath': None 
     57        'idpWhitelistConfigFilePath': None 
    5558    } 
    5659    propertyDefaults = { 
    57         'sslPeerCertAuthN': True, 
    5860        'signinInterfaceMiddlewareClass': None, 
    5961        'baseURL': '' 
     
    7981        format of propertyDefaults class variable"""     
    8082 
    81         # Default to set SSL peer cert authN where no flag is set in the config 
    82         # To override, it must explicitly be set to False in the config 
    83         if app_conf.get('sslPeerCertAuthN', 'true').lower() != 'false': 
    84              
    85             # Set parameters for SSL client connection to OpenID Provider Yadis 
    86             # retrieval URI 
    87             for paramName in self.__class__.sslPropertyDefaults: 
    88                 paramDefault = self.__class__.sslPropertyDefaults[paramName] 
    89                 setattr(self,  
    90                         paramName,  
    91                         app_conf.get(prefix+paramName, paramDefault)) 
    92                  
    93             self._initSSLPeerAuthN() 
     83        # Whitelisting of IDPs.  If no config file is set, no validation is 
     84        # executed 
     85        idpWhitelistConfigFilePath = app_conf.get( 
     86                                        prefix + 'idpWhitelistConfigFilePath') 
     87        if idpWhitelistConfigFilePath is not None: 
     88            self._initIdPValidation(idpWhitelistConfigFilePath) 
    9489         
    9590        # Check for sign in template settings 
     
    195190        referrerPathInfo = urlsplit(referrer)[2] 
    196191 
    197         if referrer and \ 
    198            not referrerPathInfo.endswith(self._authKitVerifyPath) and \ 
    199            not referrerPathInfo.endswith(self._authKitProcessPath): 
     192        if (referrer and  
     193            not referrerPathInfo.endswith(self._authKitVerifyPath) and  
     194            not referrerPathInfo.endswith(self._authKitProcessPath)): 
    200195            # Subvert authkit.authenticate.open_id.AuthOpenIDHandler.process 
    201196            # reassigning it's session 'referer' key to the URI specified in 
     
    246241        return self._app(environ, _start_response) 
    247242 
    248     def _initSSLPeerAuthN(self): 
     243    def _initIdPValidation(self, idpWhitelistConfigFilePath): 
    249244        """Initialise M2Crypto based urllib2 HTTPS handler to enable SSL  
    250245        authentication of OpenID Providers""" 
     
    252247                 "Provider ...") 
    253248         
    254         def verifySSLPeerCertCallback(preVerifyOK, x509StoreCtx): 
    255             '''SSL verify callback function used to control the behaviour when  
    256             the SSL_VERIFY_PEER flag is set 
    257              
    258             http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html 
    259              
    260             @type preVerifyOK: int 
    261             @param preVerifyOK: If a verification error is found, this  
    262             parameter will be set to 0 
    263             @type x509StoreCtx: M2Crypto.X509_Store_Context 
    264             @param x509StoreCtx: locate the certificate to be verified and  
    265             perform additional verification steps as needed 
    266             @rtype: int 
    267             @return: controls the strategy of the further verification process.  
    268             - If verify_callback returns 0, the verification process is  
    269             immediately stopped with "verification failed" state. If  
    270             SSL_VERIFY_PEER is set, a verification failure alert is sent to the 
    271             peer and the TLS/SSL handshake is terminated.  
    272             - If verify_callback returns 1, the verification process is  
    273             continued.  
    274             If verify_callback always returns 1, the TLS/SSL handshake will not 
    275             be terminated with respect to verification failures and the  
    276             connection  
    277             will be established. The calling process can however retrieve the  
    278             error code of the last verification error using  
    279             SSL_get_verify_result or by maintaining its own error storage  
    280             managed by verify_callback. 
    281             ''' 
    282             if preVerifyOK == 0: 
    283                 # Something is wrong with the certificate don't bother  
    284                 # proceeding any further 
    285                 log.error("verifyCallback: pre-verify OK flagged an error " 
    286                           "with the peer certificate, returning error state " 
    287                           "to caller ...") 
    288                 return preVerifyOK 
    289              
    290             x509Cert = x509StoreCtx.get_current_cert() 
    291             x509Cert.get_subject() 
    292             x509CertChain = x509StoreCtx.get1_chain() 
    293             for cert in x509CertChain: 
    294                 subject = cert.get_subject() 
    295                 dn = subject.as_text() 
    296                 log.debug("verifyCallback: dn = %r", dn) 
    297                  
    298             # If all is OK preVerifyOK will be 1.  Return this to the caller to 
    299             # that it's OK to proceed 
    300             return preVerifyOK 
    301             
    302         # Imports here so that if SSL Auth is not set the app will not need  
    303         # these packages  
    304         import urllib2 
    305         from M2Crypto import SSL 
    306         from M2Crypto.m2urllib2 import build_opener 
    307         from openid.fetchers import setDefaultFetcher, Urllib2Fetcher 
    308          
    309         # Create a context specifying verification of the peer but with an 
    310         # additional callback function 
    311         ctx = SSL.Context() 
    312         ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert,  
    313                        9,  
    314                        callback=verifySSLPeerCertCallback) 
    315  
    316         # Point to a directory containing CA certificates.  These must be named 
    317         # in their hashed form as expected by the OpenSSL API.  Use c_rehash 
    318         # utility to generate names or in the CA directory: 
    319         # 
    320         # $ for i in *.crt *.pem; do ln -s $i $(openssl x509 -hash -noout -in $i).0; done 
    321         ctx.load_verify_locations(capath=self.caCertDirPath) 
    322          
    323         # Load this client's certificate and private key to enable the peer  
    324         # OpenID Provider to authenticate it 
    325         ctx.load_cert(self.certFilePath,  
    326                       keyfile=self.priKeyFilePath,  
    327                       callback=lambda *arg, **kw: self.priKeyPwd) 
     249        idPValidationDriver = SSLIdPValidationDriver( 
     250                                idpConfigFilePath=idpWhitelistConfigFilePath) 
     251         
     252#        def verifySSLPeerCertCallback(preVerifyOK, x509StoreCtx): 
     253#            '''SSL verify callback function used to control the behaviour when  
     254#            the SSL_VERIFY_PEER flag is set 
     255#             
     256#            http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html 
     257#             
     258#            @type preVerifyOK: int 
     259#            @param preVerifyOK: If a verification error is found, this  
     260#            parameter will be set to 0 
     261#            @type x509StoreCtx: M2Crypto.X509_Store_Context 
     262#            @param x509StoreCtx: locate the certificate to be verified and  
     263#            perform additional verification steps as needed 
     264#            @rtype: int 
     265#            @return: controls the strategy of the further verification process.  
     266#            - If verify_callback returns 0, the verification process is  
     267#            immediately stopped with "verification failed" state. If  
     268#            SSL_VERIFY_PEER is set, a verification failure alert is sent to the 
     269#            peer and the TLS/SSL handshake is terminated.  
     270#            - If verify_callback returns 1, the verification process is  
     271#            continued.  
     272#            If verify_callback always returns 1, the TLS/SSL handshake will not 
     273#            be terminated with respect to verification failures and the  
     274#            connection  
     275#            will be established. The calling process can however retrieve the  
     276#            error code of the last verification error using  
     277#            SSL_get_verify_result or by maintaining its own error storage  
     278#            managed by verify_callback. 
     279#            ''' 
     280#            if preVerifyOK == 0: 
     281#                # Something is wrong with the certificate don't bother  
     282#                # proceeding any further 
     283#                log.error("verifyCallback: pre-verify OK flagged an error " 
     284#                          "with the peer certificate, returning error state " 
     285#                          "to caller ...") 
     286#                return preVerifyOK 
     287#             
     288#            x509Cert = x509StoreCtx.get_current_cert() 
     289#            x509Cert.get_subject() 
     290#            x509CertChain = x509StoreCtx.get1_chain() 
     291#            for cert in x509CertChain: 
     292#                subject = cert.get_subject() 
     293#                dn = subject.as_text() 
     294#                log.debug("verifyCallback: dn = %r", dn) 
     295#                 
     296#            # If all is OK preVerifyOK will be 1.  Return this to the caller to 
     297#            # that it's OK to proceed 
     298#            return preVerifyOK 
     299#            
     300#         
     301#        # Create a context specifying verification of the peer but with an 
     302#        # additional callback function 
     303#        ctx = SSL.Context() 
     304#        ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert,  
     305#                       9,  
     306#                       callback=verifySSLPeerCertCallback) 
     307# 
     308#        # Point to a directory containing CA certificates.  These must be named 
     309#        # in their hashed form as expected by the OpenSSL API.  Use c_rehash 
     310#        # utility to generate names or in the CA directory: 
     311#        # 
     312#        # $ for i in *.crt *.pem; do ln -s $i $(openssl x509 -hash -noout -in $i).0; done 
     313#        ctx.load_verify_locations(capath=self.caCertDirPath) 
     314#         
     315#        # Load this client's certificate and private key to enable the peer  
     316#        # OpenID Provider to authenticate it 
     317#        ctx.load_cert(self.certFilePath,  
     318#                      keyfile=self.priKeyFilePath,  
     319#                      callback=lambda *arg, **kw: self.priKeyPwd) 
    328320     
    329321        # Force Python OpenID library to use Urllib2 fetcher instead of the  
     
    331323        setDefaultFetcher(Urllib2Fetcher()) 
    332324         
    333         log.debug("Adding the M2Crypto SSL handler to urllib2's list of " 
    334                   "handlers...") 
    335         urllib2.install_opener(build_opener(ssl_context=ctx)) 
    336      
     325#        log.debug("Adding the M2Crypto SSL handler to urllib2's list of " 
     326#                  "handlers...") 
     327#        urllib2.install_opener(build_opener(ssl_context=ctx)) 
     328        log.debug("Setting the M2Crypto SSL handler ...") 
     329         
     330        opener = urllib2.OpenerDirector()             
     331        opener.add_handler(FlagHttpsOnlyHandler()) 
     332        opener.add_handler(HTTPSHandler(idPValidationDriver.ctx)) 
     333         
     334        urllib2.install_opener(opener) 
     335 
     336     
     337class FlagHttpsOnlyHandler(urllib2.AbstractHTTPHandler): 
     338    '''Raise an exception for any other protocol than https''' 
     339    def unknown_open(self, req): 
     340        """Signal to caller that default handler is not supported""" 
     341        raise urllib2.URLError("Only HTTPS based OpenID Providers " 
     342                               "are supported") 
     343 
     344 
    337345class SigninInterfaceError(Exception): 
    338346    """Base class for SigninInterface exceptions 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/openid/relyingparty/validation.py

    r6069 r6276  
    261261    '''Interface class for implementing OpenID Provider validators for a 
    262262    Relying Party to call''' 
     263    __slots__ = () 
    263264     
    264265    def __init__(self): 
     
    285286 
    286287class SSLClientAuthNValidator(SSLIdPValidator): 
     288    """HTTPS based validation with the addition that this client can provide 
     289    a certificate to the peer enabling mutual authentication 
     290    """ 
    287291    PARAMETERS = { 
    288292        'configFilePath': basestring, 
     
    292296        'priKeyPwd': basestring 
    293297    } 
     298    __slots__ = {} 
     299    __slots__.update(PARAMETERS) 
     300    __slots__.update({'validIdPNames': []}) 
    294301     
    295302    def __init__(self): 
    296303        """Set-up default SSL context for HTTPS requests""" 
     304        self.validIdPNames = [] 
     305         
    297306        for p in SSLClientAuthNValidator.PARAMETERS: 
    298             setattr(self, p, None) 
    299              
     307            setattr(self, p, '') 
     308 
     309    def __setattr__(self, name, value): 
     310        if (name in SSLClientAuthNValidator.PARAMETERS and  
     311            not isinstance(value, SSLClientAuthNValidator.PARAMETERS[name])): 
     312            raise TypeError('Invalid type %r for parameter "%s" expecting ' 
     313                            '%r ' %  
     314                            (type(value),  
     315                             name,  
     316                             SSLClientAuthNValidator.PARAMETERS[name])) 
     317             
     318        super(SSLClientAuthNValidator, self).__setattr__(name, value) 
     319         
    300320    def initialize(self, ctx, **parameters): 
    301321        '''@raise ConfigException:'''  
    302322        for name, val in parameters.items(): 
    303             if name not in SSLClientAuthNValidator.PARAMETERS: 
    304                 raise AttributeError('Invalid parameter name "%s".  Valid ' 
    305                                      'names are %r' % (name, 
    306                                     SSLClientAuthNValidator.PARAMETERS.keys())) 
    307                  
    308             if not isinstance(val, SSLClientAuthNValidator.PARAMETERS[name]): 
    309                 raise TypeError('Invalid type %r for parameter "%s" expecting ' 
    310                                 '%r ' %  
    311                                 (type(val),  
    312                                  name,  
    313                                  SSLClientAuthNValidator.PARAMETERS[name])) 
    314          
    315323            setattr(self, name, os.path.expandvars(val)) 
    316324              
     
    349357        x509Cert = X509Cert.fromM2Crypto(x509StoreCtx.get_current_cert()) 
    350358        commonName = x509Cert.dn['CN'] 
     359         
     360         
     361        x509CertChain = x509StoreCtx.get1_chain() 
     362        for cert in x509CertChain: 
     363            subject = cert.get_subject() 
     364            dn = subject.as_text() 
     365            log.debug("verifyCallback: dn = %r", dn) 
    351366 
    352367        # If all is OK preVerifyOK will be 1.  Return this to the caller to 
     
    580595    IDP_VALIDATOR_BASE_CLASS = SSLIdPValidator 
    581596     
    582     def __init__(self, idpConfigFilePath=None): 
     597    def __init__(self, idpConfigFilePath=None, installOpener=False): 
    583598        super(SSLIdPValidationDriver, self).__init__() 
    584599         
     
    592607                            callback=self) 
    593608 
    594         urllib2.install_opener(build_opener(ssl_context=self.ctx)) 
     609        if installOpener: 
     610            urllib2.install_opener(build_opener(ssl_context=self.ctx)) 
    595611         
    596612        if idpConfigFilePath is not None: 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/integration/__init__.py

    r6069 r6276  
    99__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1010__revision__ = "$Id: $" 
     11 
    1112 
    1213class AuthZTestApp(object): 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/integration/authz_lite/securityservices.ini

    r6271 r6276  
    123123 
    124124openid.relyingparty.baseURL = %(authkit.openid.baseurl)s 
    125 openid.relyingparty.certFilePath = %(testConfigDir)s/pki/localhost.crt 
    126 openid.relyingparty.priKeyFilePath = %(testConfigDir)s/pki/localhost.key 
    127 openid.relyingparty.priKeyPwd =  
    128 openid.relyingparty.caCertDirPath = %(testConfigDir)s/ca 
    129 openid.relyingparty.providerWhitelistFilePath = 
     125openid.relyingparty.idpWhitelistConfigFilePath = %(here)s/openidrelyingparty/ssl-idp-validator.xml 
    130126openid.relyingparty.signinInterfaceMiddlewareClass = ndg.security.server.wsgi.openid.relyingparty.signin_interface.genshi.GenshiSigninTemplate 
    131127#openid.relyingparty.signinInterface.staticContentRootDir = %(here)s/openidrelyingparty/public 
     
    284280    http://openid.net/schema/namePerson/last 
    285281    http://openid.net/schema/contact/internet/email 
     282     
     283openid.provider.trustedRelyingParties=https://localhost:7443, https://ndg.somewhere.ac.uk, 
     284        https://badc.somewhere.ac.uk 
    286285 
    287286#______________________________________________________________________________ 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/integration/authz_lite/securityservicesapp.py

    r6069 r6276  
    1515from OpenSSL import SSL 
    1616 
    17 from ndg.security.test.unit import BaseTestCase 
     17from ndg.security.test.unit import BaseTestCase, TEST_CONFIG_DIR 
    1818from ndg.security.test.unit.wsgi import PasteDeployAppServer 
    1919 
    2020INI_FILEPATH = 'securityservices.ini' 
     21 
     22os.environ['NDGSEC_INTEGRATION_TEST_DIR'] = os.path.dirname(os.path.dirname( 
     23                                                                    __file__)) 
     24os.environ[BaseTestCase.configDirEnvVarName] = TEST_CONFIG_DIR 
    2125 
    2226# To start run  
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/integration/combinedservices/services.ini

    r5656 r6276  
    419419 
    420420 
    421 #openid.provider.sregResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgSRegResponseHandler 
     421#openid.provider.sregResponse=ndg.security.server.pylons.container.lib.openid_provider_util:esgSregResponse 
    422422#openid.provider.axResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgAXResponseHandler 
    423423 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/integration/openid/securityservices.ini

    r5648 r6276  
    276276 
    277277 
    278 #openid.provider.sregResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgSRegResponseHandler 
     278#openid.provider.sregResponse=ndg.security.server.pylons.container.lib.openid_provider_util:esgSregResponse 
    279279#openid.provider.axResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgAXResponseHandler 
    280280 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/integration/openidprovider/securityservices.ini

    r5648 r6276  
    242242 
    243243 
    244 #openid.provider.sregResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgSRegResponseHandler 
     244#openid.provider.sregResponse=ndg.security.server.pylons.container.lib.openid_provider_util:esgSregResponse 
    245245#openid.provider.axResponseHandler=ndg.security.server.pylons.container.lib.openid_provider_util:esgAXResponseHandler 
    246246 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/__init__.py

    r6067 r6276  
    11"""NDG Security unit test package 
    22 
    3 NERC Data Grid Project 
     3NERC DataGrid Project 
    44""" 
    55__author__ = "P J Kershaw" 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/openid/relyingparty/validation/test_validation.py

    r6069 r6276  
    1515import unittest 
    1616from ndg.security.test.unit import BaseTestCase, mkDataDirPath 
    17 from ndg.security.server.wsgi.openid.relyingparty.validation import \ 
    18     IdPValidator, IdPValidationDriver, IdPInvalidException, \ 
    19     SSLIdPValidationDriver, SSLClientAuthNValidator 
     17from ndg.security.server.wsgi.openid.relyingparty.validation import ( 
     18    IdPValidator, IdPValidationDriver, IdPInvalidException,  
     19    SSLIdPValidationDriver, SSLClientAuthNValidator) 
    2020     
    2121     
Note: See TracChangeset for help on using the changeset viewer.