Changeset 5977 for TI12-security


Ignore:
Timestamp:
06/11/09 17:01:37 (10 years ago)
Author:
pjkersha
Message:

SQLAlchemyAttributeInterface working queries but more work needed on SAML attribute / SQL query config.

Location:
TI12-security/trunk/python
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg_security_common/ndg/security/common/X509.py

    r5953 r5977  
    765765        return cls(dn=dn) 
    766766 
     767    def __repr__(self): 
     768        """Give representation based on underlying dict object""" 
     769        return self.__dat 
     770         
    767771    def __str__(self): 
    768772        """Behaviour for print and string statements - convert DN into 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/attributeauthority.py

    r5973 r5977  
    296296                                                (value, osError.strerror)) 
    297297        self.__attCertDir = value 
     298 
     299    def _setAttributeInterface(self, value): 
     300        if not isinstance(value, AttributeInterface): 
     301            raise TypeError('Expecting %r type for "attributeInterface" ' 
     302                            'attribute; got %r' % 
     303                            (AttributeInterface, type(value))) 
     304             
     305        self.__attributeInterface = value 
    298306 
    299307    def _setTrustedHostInfo(self, value): 
     
    580588 
    581589    attributeInterface = property(fget=_getAttributeInterface,  
     590                                  fset=_setAttributeInterface, 
    582591                                  doc="Attribute Interface object") 
    583592 
     
    18731882 
    18741883 
    1875 from ndg.security.common.utils import TypedList 
    1876  
    1877 class Saml2DbAttributeMap(object): 
    1878     """Helper class for SQLAlchemyAttributeInterface.  Map SAML Attribute names 
    1879     to the SQL queries used to retrieve the values and the values themselves 
    1880     """ 
    1881     def __init__(self): 
    1882         self.__name = None 
    1883         self.__values = TypedList(basestring) 
    1884         self.__sqlQuery = None 
    1885  
    1886     def getName(self): 
    1887         return self.__name 
    1888  
    1889     def setName(self, value): 
    1890         if not isinstance(value, basestring): 
    1891             raise TypeError('Expecting string type for "name" attribute; ' 
    1892                             'got %r' % type(value)) 
    1893         self.__name = value 
    1894          
    1895     name = property(getName, setName,  
    1896                     doc="SAML attribute name") 
    1897  
    1898     def getValues(self): 
    1899         return self.__values 
    1900      
    1901     values = property(getValues,  
    1902                       doc="values returned for the given SQL query") 
    1903  
    1904     def getSqlQuery(self): 
    1905         return self.__sqlQuery 
    1906  
    1907     def setSqlQuery(self, value): 
    1908         if not isinstance(value, basestring): 
    1909             raise TypeError('Expecting string type for "sqlQuery" attribute; ' 
    1910                             'got %r' % type(value)) 
    1911         self.__sqlQuery = value 
    1912  
    1913     sqlQuery = property(getSqlQuery, setSqlQuery,  
    1914                         doc="SQL Query related to the given attribute name") 
    1915  
    1916  
    19171884import traceback 
    19181885from string import Template 
     
    19231890    sqlAlchemyInstalled = False 
    19241891     
    1925 from ndg.security.common.utils import str2Bool as _str2Bool 
    1926  
    19271892 
    19281893class SQLAlchemyAttributeInterface(AttributeInterface): 
     
    19351900     
    19361901    select attr from user_table where username = $userId 
    1937     ''' 
    1938      
    1939     str2Bool = staticmethod(_str2Bool) 
    1940      
     1902    '''     
    19411903    SQLQUERY_USERID_KEYNAME = 'userId' 
    19421904     
     
    19441906    ATTRIBUTE_SQLQUERY_OPTNAME = 'attributeSqlQuery' 
    19451907    SAML_SUBJECT_SQLQUERY_OPTNAME = 'samlSubjectSqlQuery' 
    1946     SAML_ATTRIBUTE_SQLQUERIES_OPTNAME = 'samlAttributeSqlQueries' 
    1947     SAML_ATTRIBUTE_NAMES_OPTNAME = 'samlAttributeNames' 
    19481908    SAML_VALID_REQUESTOR_DNS_OPTNAME = 'samlValidRequestorDNs' 
    19491909    SAML_ASSERTION_LIFETIME_OPTNAME = 'samlAssertionLifetime' 
    1950     SAML_ATTRIBUTE2SQLQUERY_MAP_OPTNAME = 'samlAttribute2SqlQueryMap' 
     1910    SAML_ATTRIBUTE2SQLQUERY_OPTNAME = 'samlAttribute2SqlQuery' 
     1911     
     1912    SAML_ATTRIBUTE2SQLQUERY_ATTRNAME_DELIMITERS = ('.', '_') 
     1913    SAML_ATTRIBUTE2SQLQUERY_ATTRNAME_RE = re.compile('%s[%s]' %                                                    
     1914        (SAML_ATTRIBUTE2SQLQUERY_OPTNAME, 
     1915         ''.join(SAML_ATTRIBUTE2SQLQUERY_ATTRNAME_DELIMITERS)) 
     1916    ) 
    19511917     
    19521918    __slots__ = ( 
     
    19541920        ATTRIBUTE_SQLQUERY_OPTNAME, 
    19551921        SAML_SUBJECT_SQLQUERY_OPTNAME, 
    1956         SAML_ATTRIBUTE_SQLQUERIES_OPTNAME, 
    1957         SAML_ATTRIBUTE_NAMES_OPTNAME, 
    19581922        SAML_VALID_REQUESTOR_DNS_OPTNAME, 
    19591923        SAML_ASSERTION_LIFETIME_OPTNAME, 
    1960         SAML_ATTRIBUTE2SQLQUERY_MAP_OPTNAME, 
     1924        SAML_ATTRIBUTE2SQLQUERY_OPTNAME, 
    19611925    ) 
    19621926    __PRIVATE_ATTR_PREFIX = '_SQLAlchemyAttributeInterface__' 
    19631927    __slots__ += tuple([__PRIVATE_ATTR_PREFIX + i for i in __slots__]) 
     1928    del i 
    19641929     
    19651930    def __init__(self, **properties): 
    1966         '''Instantiate object taking in settings from the input 
    1967         properties''' 
     1931        '''Instantiate object taking in settings from the input properties''' 
    19681932        log.debug('Initialising SQLAlchemyAttributeInterface instance ...') 
    19691933         
     
    19741938        self.__attributeSqlQuery = None 
    19751939        self.__samlSubjectSqlQuery = None 
    1976         self.__samlAttributeSqlQueries = None 
    1977         self.__samlAttributeNames = None 
    19781940        self.__samlValidRequestorDNs = None 
    19791941        self.__samlAssertionLifetime = None 
    1980         self.__samlAttribute2SqlQueryMap = {} 
     1942        self.__samlAttribute2SqlQuery = {} 
    19811943         
    19821944        self.setProperties(**properties) 
     
    19861948        attribute names containing the SAML attribute name as a suffix e.g. 
    19871949         
    1988         attributeInterface.samlAttribute2SqlQueryMap_firstName = 'Philip' 
    1989          
    1990         will update __samlAttribute2SqlQueryMap with the 'firstName', 'Philip' 
     1950        attributeInterface.samlAttribute2SqlQuery_firstName = 'Philip' 
     1951         
     1952        will update __samlAttribute2SqlQuery with the 'firstName', 'Philip' 
    19911953        key value pair.  Similarly, 
    19921954         
    1993         setattr('samlAttribute2SqlQueryMap.emailAddress', 'pjk@somewhere.ac.uk') 
    1994          
    1995         sets __samlAttribute2SqlQueryMap with the 'emailAddress', 
     1955        setattr('samlAttribute2SqlQuery.emailAddress', 'pjk@somewhere.ac.uk') 
     1956         
     1957        sets __samlAttribute2SqlQuery with the 'emailAddress', 
    19961958        'pjk@somewhere.ac.uk' key value pair 
     1959         
     1960        This is useful in enabling settings to be made direct from a dict of 
     1961        option name and values parsed from an ini file. 
    19971962        """ 
    1998         if (name != 'samlAttribute2SqlQueryMap' and 
    1999             name.startswith('samlAttribute2SqlQueryMap')): 
    2000              
    2001             suffix = name.replace('samlAttribute2SqlQueryMap','') 
    2002             if suffix[0] not in ('.', '_'): 
    2003                 raise AttributeError('Expecting "." or "_" separator for ' 
    2004                                      'special "samlAttribute2SqlQueryMap*" ' 
    2005                                      'attribute setting') 
    2006                  
    2007             samlAttributeName = suffix[1:] 
    2008             self.__samlAttribute2SqlQueryMap[samlAttributeName] = value 
     1963        if name in SQLAlchemyAttributeInterface.__slots__: 
     1964            object.__setattr__(self, name, value) 
    20091965        else: 
    2010             object.__setattr__(self, name, value) 
     1966            r = SQLAlchemyAttributeInterface.SAML_ATTRIBUTE2SQLQUERY_ATTRNAME_RE 
     1967            attributeNameSplit = r.split(name) 
     1968            if len(attributeNameSplit) == 2: 
     1969                # A special 'samlAttribute2SqlQuery*' attribute name has been  
     1970                # found ...             
     1971                samlAttributeName = attributeNameSplit[1] 
     1972                self.__samlAttribute2SqlQuery[samlAttributeName] = value 
     1973            else: 
     1974                raise AttributeError("'SQLAlchemyAttributeInterface' has no " 
     1975                                     "attribute %r" % name) 
    20111976 
    20121977    def setProperties(self, **properties): 
     
    20532018                                   doc="SAML Subject SQL Query") 
    20542019 
    2055     def _getSamlAttribute2SqlQueryMap(self): 
    2056         return self.__samlAttribute2SqlQueryMap 
    2057  
    2058     def _setSamlAttribute2SqlQueryMap(self, value): 
     2020    def _getSamlAttribute2SqlQuery(self): 
     2021        return self.__samlAttribute2SqlQuery 
     2022 
     2023    def _setSamlAttribute2SqlQuery(self, value): 
    20592024        if isinstance(value, dict): 
    20602025            # Validate string type for keys and values 
     
    20632028                                not isinstance(v, basestring))] 
    20642029            if invalidItems: 
    2065                 raise TypeError('Expecting string type for ' 
    2066                                 '"samlAttribute2SqlQueryMap" dict items; ' 
     2030                raise TypeError('Expecting string type for "%s" dict items; ' 
    20672031                                'got these/this invalid item(s) %r' %  
    2068                                 invalidItems) 
     2032                (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE2SQLQUERY_OPTNAME, 
     2033                 invalidItems)) 
    20692034                 
    2070             self.__samlAttribute2SqlQueryMap = value 
     2035            self.__samlAttribute2SqlQuery = value 
    20712036             
    20722037        elif isinstance(value, (tuple, list)): 
     
    20752040                    raise TypeError('Expecting string type for "%s" ' 
    20762041                                    'attribute items; got %r' % 
    2077                 (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE2SQLQUERY_MAP_OPTNAME, 
     2042                (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE2SQLQUERY_OPTNAME, 
    20782043                 type(value))) 
    20792044                     
    2080             self.__samlAttribute2SqlQueryMap = value                  
     2045            self.__samlAttribute2SqlQuery = value                  
    20812046        else: 
    2082             raise TypeError('Expecting dict type for ' 
    2083                             '"samlAttribute2SqlQueryMap" attribute; got %r' % 
    2084             (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE2SQLQUERY_MAP_OPTNAME, 
    2085              type(value))) 
    2086              
    2087  
    2088     samlAttribute2SqlQueryMap = property(_getSamlAttribute2SqlQueryMap,  
    2089                                          _setSamlAttribute2SqlQueryMap,  
    2090                                          doc="SQL Query or queries to obtain the " 
    2091                                            "attribute information to respond " 
    2092                                            "a SAML attribute query.  The " 
    2093                                            "attributes returned from each " 
    2094                                            "query concatenated together, must " 
    2095                                            "exactly match the SAML attribute " 
    2096                                            "names set in the samlAttributeNames " 
    2097                                            "property") 
    2098  
    2099     def _getSamlAttributeNames(self): 
    2100         return self.__samlAttributeNames 
    2101  
    2102     def _setSamlAttributeNames(self, value): 
    2103         if isinstance(value, basestring): 
    2104             self.__samlAttributeNames = [name for name in value.split()] 
    2105              
    2106         elif isinstance(value, (tuple, list)): 
    2107             for name in value: 
    2108                 if not isinstance(name, basestring): 
    2109                     raise TypeError('Expecting string type for "%s" ' 
    2110                                     'attribute items; got %r' % 
    2111                     (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE_NAMES_OPTNAME, 
    2112                      type(value))) 
    2113                      
    2114             self.__samlAttributeNames = value 
    2115         else: 
    2116             raise TypeError('Expecting list/tuple or string type for "%s" ' 
    2117                     'attribute; got %r' % 
    2118                     (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE_NAMES_OPTNAME, 
    2119                      type(value))) 
    2120              
    2121     samlAttributeNames = property(_getSamlAttributeNames,  
    2122                                   _setSamlAttributeNames,  
    2123                                   doc="Attribute names that the Attribute " 
    2124                                       "Authority supports retrieval of via " 
    2125                                       "its SAML Attribute query interface.  " 
    2126                                       "The order of these names is significant:" 
    2127                                       " the order must map directly to the " 
    2128                                       "results of the samlAttributeSqlQueries " 
    2129                                       "as retrieved by the " 
    2130                                       "_queryDbForSamlAttributes method") 
     2047            raise TypeError('Expecting dict type for "%s" attribute; got %r' % 
     2048                (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE2SQLQUERY_OPTNAME, 
     2049                 type(value))) 
     2050             
     2051    samlAttribute2SqlQuery = property(_getSamlAttribute2SqlQuery,  
     2052                                      _setSamlAttribute2SqlQuery,  
     2053                                      doc="SQL Query or queries to obtain the " 
     2054                                          "attribute information to respond " 
     2055                                          "a SAML attribute query.  The " 
     2056                                          "attributes returned from each " 
     2057                                          "query concatenated together, must " 
     2058                                          "exactly match the SAML attribute " 
     2059                                          "names set in the samlAttributeNames " 
     2060                                          "property") 
    21312061 
    21322062    def _getSamlValidRequestorDNs(self): 
     
    21802110                                 fset=_setAttributeSqlQuery,  
    21812111                                 doc="SQL Query for attribute query") 
    2182  
     2112     
    21832113    def getRoles(self, userId):      
    21842114        """Return valid roles for the given userId 
     
    22412171        requestorDN = X500DN.fromString(attributeQuery.issuer.value) 
    22422172 
    2243         if not self._queryDbForSamlSubject(userId)(userId): 
     2173        if not self._queryDbForSamlSubject(userId): 
    22442174            raise UserIdNotKnown('Subject Id "%s" is not known to this ' 
    22452175                                 'authority' % userId) 
     
    22502180 
    22512181        unknownAttrNames = [attrName for attrName in requestedAttributeNames 
    2252                             if attrName not in self.samlAttributeNames] 
     2182                            if attrName not in self.samlAttribute2SqlQuery] 
    22532183 
    22542184        if len(unknownAttrNames) > 0: 
    22552185            raise AttributeNotKnownError("Unknown attributes requested: %r" % 
    22562186                                         unknownAttrNames) 
    2257  
    2258         # Query the database for the supported attributes and return them 
    2259         # mapped to their attribute names as specified by the attributeNames 
    2260         # property 
    2261         attributeMap = self._queryDbForSamlAttributes(userId) 
    22622187         
    22632188        # Create a new assertion to hold the attributes to be returned 
     
    22802205        attributeStatement = AttributeStatement() 
    22812206 
    2282         # Add test set of attributes 
     2207        # Query the database for the requested attributes and return them 
     2208        # mapped to their attribute names as specified by the attributeNames 
     2209        # property 
    22832210        for requestedAttribute in attributeQuery.attributes: 
     2211            attributeVals = self._queryDbForSamlAttributes( 
     2212                                                    requestedAttribute.name,  
     2213                                                    userId) 
     2214 
     2215            # Make a new SAML attribute object to hold the values obtained 
    22842216            attribute = Attribute() 
    22852217            attribute.name = requestedAttribute.name 
     2218             
     2219            # TODO: check name format requested - only XSString is currently 
     2220            # supported 
    22862221            attribute.nameFormat = requestedAttribute.nameFormat 
    22872222 
     
    22892224                attribute.friendlyName = requestedAttribute.friendlyName 
    22902225 
    2291             if attribute.name in self.samlAttributeNames: 
    2292                 attributeVals = attributeMap[attribute.name] 
    2293 #                for val in badcAttributeVals: 
    2294 #                    attribute.attributeValues.append(XSStringAttributeValue()) 
    2295 #                    attribute.attributeValues[-1].value = val 
    2296 # 
    2297 #            elif attribute.name == CSVFileAttributeInterface.EMAILADDR_ATTR_NAME: 
    2298 #                attribute.attributeValues.append(XSStringAttributeValue()) 
    2299 #                attribute.attributeValues[-1].value = self.attributeMap[ 
    2300 #                        userId][CSVFileAttributeInterface.EMAILADDR_ATTR_INDEX] 
    2301 # 
    2302 #            elif attribute.name == CSVFileAttributeInterface.FIRSTNAME_ATTR_NAME: 
    2303 #                attribute.attributeValues.append(XSStringAttributeValue()) 
    2304 #                attribute.attributeValues[-1].value = self.attributeMap[ 
    2305 #                        userId][CSVFileAttributeInterface.FIRSTNAME_ATTR_INDEX] 
    2306 # 
    2307 #            elif attribute.name == CSVFileAttributeInterface.LASTNAME_ATTR_NAME: 
    2308 #                attribute.attributeValues.append(XSStringAttributeValue()) 
    2309 #                attribute.attributeValues[-1].value = self.attributeMap[ 
    2310 #                        userId][CSVFileAttributeInterface.LASTNAME_ATTR_INDEX] 
     2226            attribute.attributeValues.append(XSStringAttributeValue()) 
     2227            for val in attributeVals: 
     2228                attribute.attributeValues[-1].value = val 
    23112229 
    23122230            attributeStatement.attributes.append(attribute) 
     
    23292247            return True 
    23302248         
     2249        if self.connectionString is None: 
     2250            raise AttributeInterfaceConfigError('No "connectionString" setting ' 
     2251                                                'has been made') 
     2252             
    23312253        dbEngine = create_engine(self.connectionString) 
    2332         connection = dbEngine.connect() 
    23332254         
    23342255        try: 
    23352256            queryInputs = { 
    2336                 SQLAlchemyAttributeInterface.SQLQUERY_USERID_KEYNAME: 
    2337                 userId 
     2257                SQLAlchemyAttributeInterface.SQLQUERY_USERID_KEYNAME: userId 
    23382258            } 
    23392259            query = Template(self.samlSubjectSqlQuery).substitute(queryInputs) 
     2260             
     2261        except KeyError, e: 
     2262            raise AttributeInterfaceConfigError("Invalid key for SAML subject " 
     2263                        "query string.  The valid key is %r" %  
     2264                        SQLAlchemyAttributeInterface.SQLQUERY_USERID_KEYNAME)     
     2265 
     2266        try: 
     2267            connection = dbEngine.connect() 
    23402268            result = connection.execute(query) 
    23412269 
     
    23472275 
    23482276        try: 
    2349             found = [entry for entry in result][0][0] 
     2277            found = [entry for entry in result][0][0] > 0 
    23502278         
    23512279        except (IndexError, TypeError): 
     
    23532281                                                  traceback.format_exc()) 
    23542282         
    2355         log.debug('user=%r found=%r' % (username, found)) 
     2283        log.debug('user=%r found=%r' % (userId, found)) 
    23562284         
    23572285        return found 
    23582286      
    2359     def _queryDbForSamlAttributes(self, userId):      
     2287    def _queryDbForSamlAttributes(self, attributeName, userId):      
    23602288        """Query the database in response to a SAML attribute query 
    23612289         
     
    23672295        @return: True/False is user registered? 
    23682296        """ 
     2297         
     2298        if self.connectionString is None: 
     2299            raise AttributeInterfaceConfigError('No "connectionString" setting ' 
     2300                                                'has been made') 
    23692301 
    23702302        dbEngine = create_engine(self.connectionString) 
    2371         connection = dbEngine.connect() 
    2372          
    2373         attributes = ()  
    2374          
    2375         for queryTmpl in self.samlAttributeSqlQueries: 
    2376             try: 
    2377                 queryInputs = { 
    2378                     SQLAlchemyAttributeInterface.SQLQUERY_USERID_KEYNAME: 
    2379                     userId 
    2380                 } 
    2381                 query = Template(queryTmpl).substitute(queryInputs) 
    2382                 result = connection.execute(query) 
    2383      
    2384             except exc.ProgrammingError: 
    2385                 raise AttributeInterfaceRetrieveError("Error with SQL Syntax: " 
    2386                                                       "%s" % 
    2387                                                       traceback.format_exc()) 
    2388             finally: 
    2389                 connection.close() 
    2390  
     2303         
     2304        queryTmpl = self.samlAttribute2SqlQuery.get(attributeName) 
     2305        if queryTmpl is None: 
     2306            # TODO: how to handle this error? 
     2307            raise Exception() 
     2308         
    23912309        try: 
    2392             found = [entry for entry in result][0][0] 
    2393          
     2310            queryInputs = { 
     2311                SQLAlchemyAttributeInterface.SQLQUERY_USERID_KEYNAME: userId 
     2312            } 
     2313            query = Template(queryTmpl).substitute(queryInputs) 
     2314             
     2315        except KeyError, e: 
     2316            raise AttributeInterfaceConfigError("Invalid key for SAML " 
     2317                        "attribute query string.  The valid key is %r" %  
     2318                        SQLAlchemyAttributeInterface.SQLQUERY_USERID_KEYNAME) 
     2319                 
     2320        try: 
     2321            connection = dbEngine.connect() 
     2322            result = connection.execute(query) 
     2323 
     2324        except exc.ProgrammingError: 
     2325            raise AttributeInterfaceRetrieveError("Error with SQL Syntax: " 
     2326                                                  "%s" % 
     2327                                                  traceback.format_exc()) 
     2328        finally: 
     2329            connection.close() 
     2330 
     2331        try: 
     2332            attributeValues = [entry for entry in result][0] 
     2333             
    23942334        except (IndexError, TypeError): 
    2395             raise AttributeInterfaceRetrieveError("Error with result set: %s" % 
     2335            raise AttributeInterfaceRetrieveError("Error with result set: " 
     2336                                                  "%s" % 
    23962337                                                  traceback.format_exc()) 
    23972338         
    2398         log.debug('user=%r found=%r' % (username, found)) 
    2399          
    2400         attributeMap = dict(zip(self.samlAttributeNames, attributes)) 
    2401          
    2402         return attributeMap 
     2339        log.debug('Database results for SAML Attribute query user=%r ' 
     2340                  'attribute values=%r' % (userId, attributeValues)) 
     2341         
     2342        return attributeValues 
    24032343       
    24042344    def __getstate__(self): 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/__init__.py

    r5971 r5977  
    5858    DB_CONNECTION_STR = 'sqlite:///%s' % DB_FILENAME 
    5959    USERNAME = 'pjk' 
     60    OPENID_URI_STEM = 'https://openid.localhost/' 
    6061    OPENID_IDENTIFIER = 'philip.kershaw' 
    6162    FIRSTNAME = 'Philip' 
    6263    LASTNAME = 'Kershaw' 
    6364    EMAILADDRESS = 'pjk@somewhere.ac.uk' 
     65     
     66    ATTRIBUTE_NAMES = ( 
     67        "urn:siteA:security:authz:1.0:attr", 
     68    ) 
     69 
    6470    ATTRIBUTE_VALUES = ( 
    6571        'urn:siteA:security:authz:1.0:attr:postdoc', 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/attributeauthority/test_attributeauthority.py

    r5973 r5977  
    242242 
    243243from warnings import warn 
    244      
     244from uuid import uuid4 
     245from datetime import datetime 
     246from saml.saml2.core import (Response, Attribute, SAMLVersion, Subject, NameID, 
     247                             Issuer, AttributeQuery, XSStringAttributeValue,  
     248                             Status, StatusMessage, StatusCode) 
     249from saml.xml import XMLConstants 
     250 
     251 
    245252class SQLAlchemyAttributeInterfaceTestCase(BaseTestCase): 
     253    SAML_SUBJECT_SQLQUERY = ("select count(*) from users where '%s' || " 
     254                             "openid_identifier = '${userId}'" % 
     255                             BaseTestCase.OPENID_URI_STEM) 
     256     
     257    SAML_FIRSTNAME_SQLQUERY = ("select firstname from users where '%s' || " 
     258                               "openid_identifier = '${userId}'" % 
     259                               BaseTestCase.OPENID_URI_STEM) 
     260             
     261    SAML_LASTNAME_SQLQUERY = ("select lastname from users where '%s' || " 
     262                              "openid_identifier = '${userId}'" % 
     263                              BaseTestCase.OPENID_URI_STEM) 
     264         
     265    SAML_EMAILADDRESS_SQLQUERY = ("select emailaddress from users where '%s' || " 
     266                                  "openid_identifier = '${userId}'" % 
     267                                  BaseTestCase.OPENID_URI_STEM) 
     268         
     269    SAML_ATTRIBUTES_SQLQUERY = ("select attributename from attributes where " 
     270                                "'%s' || openid_identifier = '${userId}'" % 
     271                                BaseTestCase.OPENID_URI_STEM) 
     272                                 
    246273    def __init__(self, *arg, **kw): 
    247274        super(SQLAlchemyAttributeInterfaceTestCase, self).__init__(*arg, **kw) 
     
    256283            self.skipTests = True 
    257284         
    258     def test01(self): 
     285    def test01TrySamlAttribute2SqlQuery__setattr__(self): 
    259286        if self.skipTests: 
    260287            return 
    261288         
    262289        attributeInterface = SQLAlchemyAttributeInterface() 
    263         attributeInterface.samlAttribute2SqlQueryMap_firstName = 'Philip' 
    264         setattr(attributeInterface, 'samlAttribute2SqlQueryMap.lastName', 
    265                 'Kershaw') 
    266         attributeInterface.samlAttribute2SqlQueryMap['emailAddress'] = ('pjk' 
    267                                                             '@somewhere.ac.uk') 
    268  
    269                                  
     290         
     291        # Define queries for SAML attribute names 
     292        attributeInterface.samlAttribute2SqlQuery_firstName = \ 
     293            SQLAlchemyAttributeInterfaceTestCase.SAML_FIRSTNAME_SQLQUERY 
     294             
     295        setattr(attributeInterface, 'samlAttribute2SqlQuery.lastName', 
     296            SQLAlchemyAttributeInterfaceTestCase.SAML_LASTNAME_SQLQUERY) 
     297         
     298        attributeInterface.samlAttribute2SqlQuery['emailAddress'] = ( 
     299            SQLAlchemyAttributeInterfaceTestCase.SAML_EMAILADDRESS_SQLQUERY) 
     300         
     301        attributeInterface.samlAttribute2SqlQuery_attributes = ( 
     302            SQLAlchemyAttributeInterfaceTestCase.SAML_ATTRIBUTES_SQLQUERY) 
     303         
     304    def test02SetProperties(self): 
     305        # test setProperties interface for instance attribute assignment 
     306        if self.skipTests: 
     307            return 
     308         
     309        properties = { 
     310            'connectionString':  
     311                SQLAlchemyAttributeInterfaceTestCase.DB_CONNECTION_STR, 
     312             
     313            'samlSubjectSqlQuery': 
     314                SQLAlchemyAttributeInterfaceTestCase.SAML_SUBJECT_SQLQUERY, 
     315                 
     316            'samlAttribute2SqlQuery.urn:esg:first:name': 
     317                SQLAlchemyAttributeInterfaceTestCase.SAML_FIRSTNAME_SQLQUERY, 
     318             
     319            'samlAttribute2SqlQuery.urn:esg:last:name': 
     320                SQLAlchemyAttributeInterfaceTestCase.SAML_LASTNAME_SQLQUERY, 
     321         
     322            'samlAttribute2SqlQuery.urn:esg:first:email:address': 
     323                SQLAlchemyAttributeInterfaceTestCase.SAML_EMAILADDRESS_SQLQUERY, 
     324         
     325            'samlAttribute2SqlQuery_attributes': 
     326                SQLAlchemyAttributeInterfaceTestCase.SAML_ATTRIBUTES_SQLQUERY, 
     327             
     328            'samlValidRequestorDNs': ('/O=STFC/OU=CEDA/CN=AuthorisationService', 
     329                                      '/O=ESG/OU=NCAR/CN=Gateway'), 
     330            'samlAssertionLifetime': 86400, 
     331 
     332        } 
     333        attributeInterface = SQLAlchemyAttributeInterface() 
     334        attributeInterface.setProperties(**properties) 
     335         
     336        self.assert_(attributeInterface.samlAttribute2SqlQuery['firstName'] == \ 
     337            SQLAlchemyAttributeInterfaceTestCase.SAML_FIRSTNAME_SQLQUERY) 
     338         
     339        self.assert_(attributeInterface.connectionString == \ 
     340                     SQLAlchemyAttributeInterfaceTestCase.DB_CONNECTION_STR) 
     341         
     342        # Test constructor setting properties 
     343        attributeInterface2 = SQLAlchemyAttributeInterface(**properties) 
     344        self.assert_(attributeInterface2.samlAssertionLifetime.days == 1) 
     345         
     346    def test03SamlAttributeQuery(self): 
     347        if self.skipTests: 
     348            return 
     349         
     350        # Prepare a client query 
     351        attributeQuery = AttributeQuery() 
     352        attributeQuery.version = SAMLVersion(SAMLVersion.VERSION_20) 
     353        attributeQuery.id = str(uuid4()) 
     354        attributeQuery.issueInstant = datetime.utcnow() 
     355         
     356        attributeQuery.issuer = Issuer() 
     357        attributeQuery.issuer.format = Issuer.X509_SUBJECT 
     358        attributeQuery.issuer.value = '/O=ESG/OU=NCAR/CN=Gateway' 
     359                         
     360                         
     361        attributeQuery.subject = Subject()   
     362        attributeQuery.subject.nameID = NameID() 
     363        attributeQuery.subject.nameID.format = "urn:esg:openid" 
     364        attributeQuery.subject.nameID.value = \ 
     365                                    "https://openid.localhost/philip.kershaw" 
     366         
     367        fnAttribute = Attribute() 
     368        fnAttribute.name = "urn:esg:first:name" 
     369        fnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string" 
     370        fnAttribute.friendlyName = "FirstName" 
     371 
     372        attributeQuery.attributes.append(fnAttribute) 
     373     
     374        lnAttribute = Attribute() 
     375        lnAttribute.name = "urn:esg:last:name" 
     376        lnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string" 
     377        lnAttribute.friendlyName = "LastName" 
     378 
     379        attributeQuery.attributes.append(lnAttribute) 
     380     
     381        emailAddressAttribute = Attribute() 
     382        emailAddressAttribute.name = "urn:esg:email:address" 
     383        emailAddressAttribute.nameFormat = XMLConstants.XSD_NS+"#"+\ 
     384                                    XSStringAttributeValue.TYPE_LOCAL_NAME 
     385        emailAddressAttribute.friendlyName = "emailAddress" 
     386 
     387        attributeQuery.attributes.append(emailAddressAttribute)                                    
     388     
     389        authzAttribute = Attribute() 
     390        authzAttribute.name = \ 
     391            SQLAlchemyAttributeInterfaceTestCase.ATTRIBUTE_NAMES[0] 
     392        authzAttribute.nameFormat = XMLConstants.XSD_NS+"#"+\ 
     393                                    XSStringAttributeValue.TYPE_LOCAL_NAME 
     394        authzAttribute.friendlyName = "authz" 
     395 
     396        attributeQuery.attributes.append(authzAttribute)                                    
     397         
     398        # Add the response - the interface will populate with an assertion as 
     399        # appropraite 
     400        samlResponse = Response() 
     401         
     402        samlResponse.issueInstant = datetime.utcnow() 
     403        samlResponse.id = str(uuid4()) 
     404        samlResponse.issuer = Issuer() 
     405         
     406        # Initialise to success status but reset on error 
     407        samlResponse.status = Status() 
     408        samlResponse.status.statusCode = StatusCode() 
     409        samlResponse.status.statusMessage = StatusMessage() 
     410        samlResponse.status.statusCode.value = StatusCode.SUCCESS_URI 
     411         
     412        # Nb. SAML 2.0 spec says issuer format must be omitted 
     413        samlResponse.issuer.value = "CEDA" 
     414         
     415        samlResponse.inResponseTo = attributeQuery.id 
     416         
     417        # Set up the interface object 
     418         
     419        # Define queries for SAML attribute names 
     420        samlAttribute2SqlQuery = { 
     421            'firstName':  
     422                SQLAlchemyAttributeInterfaceTestCase.SAML_FIRSTNAME_SQLQUERY, 
     423             
     424            'lastName':  
     425                SQLAlchemyAttributeInterfaceTestCase.SAML_LASTNAME_SQLQUERY, 
     426         
     427            'emailAddress':  
     428                SQLAlchemyAttributeInterfaceTestCase.SAML_EMAILADDRESS_SQLQUERY, 
     429         
     430            'attributes':  
     431                SQLAlchemyAttributeInterfaceTestCase.SAML_ATTRIBUTES_SQLQUERY,                                
     432        } 
     433         
     434        attributeInterface = SQLAlchemyAttributeInterface( 
     435                                samlAttribute2SqlQuery=samlAttribute2SqlQuery) 
     436         
     437        attributeInterface.connectionString = \ 
     438                        SQLAlchemyAttributeInterfaceTestCase.DB_CONNECTION_STR 
     439                 
     440        attributeInterface.samlValidRequestorDNs = ( 
     441            '/O=STFC/OU=CEDA/CN=AuthorisationService', 
     442            '/O=ESG/OU=NCAR/CN=Gateway') 
     443         
     444        attributeInterface.setProperties(samlAssertionLifetime=28800.) 
     445         
     446        attributeInterface.samlSubjectSqlQuery = ( 
     447            SQLAlchemyAttributeInterfaceTestCase.SAML_SUBJECT_SQLQUERY) 
     448         
     449        # Make the query 
     450        attributeInterface.getAttributes(attributeQuery, samlResponse) 
     451         
     452        self.assert_( 
     453                samlResponse.status.statusCode.value == StatusCode.SUCCESS_URI) 
     454        self.assert_(samlResponse.inResponseTo == attributeQuery.id) 
     455        self.assert_(samlResponse.assertions[0].subject.nameID.value == \ 
     456                     attributeQuery.subject.nameID.value) 
     457 
     458         
    270459if __name__ == "__main__": 
    271460    unittest.main() 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/saml/test_samlinterface.py

    r5739 r5977  
    2424from ndg.security.common.utils.etree import QName, prettyPrint 
    2525 
    26 from saml.saml2.core import Response, Assertion, Attribute, AttributeValue, \ 
    27     AttributeStatement, SAMLVersion, Subject, NameID, Issuer, AttributeQuery, \ 
    28     XSStringAttributeValue, XSGroupRoleAttributeValue, Conditions, Status, \ 
    29     StatusCode 
     26from saml.saml2.core import (Response, Assertion, Attribute,  
     27                             AttributeStatement, SAMLVersion, Subject, NameID, 
     28                             Issuer, AttributeQuery, XSStringAttributeValue,  
     29                             XSGroupRoleAttributeValue, Conditions, Status,  
     30                             StatusCode) 
    3031from saml.xml import XMLConstants 
    31 from saml.xml.etree import AssertionElementTree, AttributeQueryElementTree, \ 
    32     ResponseElementTree, XSGroupRoleAttributeValueElementTree 
     32from saml.xml.etree import (AttributeQueryElementTree, ResponseElementTree,  
     33                            XSGroupRoleAttributeValueElementTree) 
    3334 
    3435 
Note: See TracChangeset for help on using the changeset viewer.