Changeset 5971


Ignore:
Timestamp:
04/11/09 17:10:50 (10 years ago)
Author:
pjkersha
Message:

Adding SQLAlchemy based AttributeInterface? class for Attribute Authority

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

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/Tests/configparser/configparser.py

    r5329 r5971  
    1111__revision__ = '$Id$' 
    1212 
    13 from ConfigParser import SafeConfigParser 
     13from ndg.security.common.utils.configfileparsers import ( 
     14                                                    CaseSensitiveConfigParser) 
    1415 
    1516class MyConfigFileError(Exception): 
  • TI12-security/trunk/python/Tests/configparser/my.cfg

    r5329 r5971  
    11[DEFAULT] 
    22myString: Hello! 
     3        Hello again 
     4        Good-bye! 
     5        See you later 
    36myInt: 1000 
    47myBool: False 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/attributeauthority.py

    r5791 r5971  
    2727from uuid import uuid4 
    2828from datetime import datetime, timedelta 
     29 
    2930from saml.utils import SAMLDateTime 
    30 from saml.saml2.core import Response, Assertion, Attribute, AttributeValue, \ 
    31     AttributeStatement, SAMLVersion, Subject, NameID, Issuer, AttributeQuery, \ 
    32     XSStringAttributeValue, XSGroupRoleAttributeValue, Conditions, Status, \ 
    33     StatusCode, StatusMessage 
     31from saml.saml2.core import (Response, Assertion, Attribute, AttributeValue,  
     32    AttributeStatement, SAMLVersion, Subject, NameID, Issuer, AttributeQuery,  
     33    XSStringAttributeValue, XSGroupRoleAttributeValue, Conditions, Status,  
     34    StatusCode, StatusMessage) 
    3435     
    3536from saml.common.xml import SAMLConstants 
    36 from saml.xml.etree import AssertionElementTree, AttributeQueryElementTree, \ 
    37     ResponseElementTree, XSGroupRoleAttributeValueElementTree 
     37from saml.xml.etree import (AssertionElementTree, AttributeQueryElementTree,  
     38    ResponseElementTree, XSGroupRoleAttributeValueElementTree) 
    3839 
    3940from ndg.security.common.utils import TypedList 
    4041from ndg.security.common.utils.classfactory import instantiateClass 
    41 from ndg.security.common.utils.configfileparsers import \ 
    42     CaseSensitiveConfigParser 
     42from ndg.security.common.utils.configfileparsers import ( 
     43    CaseSensitiveConfigParser, ) 
    4344     
    4445# X.509 Certificate handling 
    45 from ndg.security.common.X509 import X509Cert 
     46from ndg.security.common.X509 import X509Cert, X500DN 
    4647 
    4748# NDG Attribute Certificate 
     
    15541555    """Exception handling for NDG Attribute Authority User Roles interface 
    15551556    class.""" 
     1557  
     1558                       
     1559class AttributeInterfaceConfigError(Exception): 
     1560    """Invalid configuration set for Attribute interface""" 
     1561  
     1562                       
     1563class AttributeInterfaceRetrieveError(Exception): 
     1564    """Error retrieving attributes for Attribute interface class""" 
    15561565 
    15571566                        
     
    15851594    Roles are expected to indexed by user Distinguished Name (DN).  They 
    15861595    could be stored in a database or file.""" 
    1587  
     1596     
     1597    # Enable derived classes to use slots if desired 
     1598    __slots__ = () 
     1599     
    15881600    # User defined class may wish to specify a URI for a database interface or 
    15891601    # path for a user roles configuration file 
     
    16791691    """User Roles interface to Postgres database 
    16801692     
    1681     The SAML getAttributes method is NOT implemented""" 
     1693    The SAML getAttributes method is NOT implemented 
     1694     
     1695    The configuration file follows the form, 
     1696     
     1697    [Connection] 
     1698    # name of database 
     1699    dbName: user.db 
     1700     
     1701    # database host machine 
     1702    host: mydbhost.ac.uk 
     1703     
     1704    # database account username 
     1705    username: mydbaccount 
     1706     
     1707    # Password - comment out to prompt from stdin instead 
     1708    pwd: mydbpassword 
     1709     
     1710    [getRoles] 
     1711    query0: select distinct grp from users_table, where user = '%%s' 
     1712    defaultRoles = publicRole 
     1713    """ 
    16821714 
    16831715    CONNECTION_SECTION_NAME = "Connection" 
     
    18031835                                          "\"%s\": %s" % (dbName, e)) 
    18041836 
    1805  
    18061837    def close(self): 
    18071838        """Close database connection""" 
     
    18401871 
    18411872    cursor = property(fget=__getCursor, doc="database cursor") 
     1873 
     1874 
     1875from ndg.security.common.utils import TypedList 
     1876 
     1877class 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 
     1917import traceback 
     1918from string import Template 
     1919try: 
     1920    from sqlalchemy import create_engine, exc 
     1921    sqlAlchemyInstalled = True 
     1922except ImportError: 
     1923    sqlAlchemyInstalled = False 
     1924     
     1925from ndg.security.common.utils import str2Bool as _str2Bool 
     1926 
     1927 
     1928class SQLAlchemyAttributeInterface(AttributeInterface): 
     1929    '''SQLAlchemy based Attribute interface enables the Attribute Authority 
     1930    to interface to any database type supported by it 
     1931     
     1932    @type SQLQUERY_USERID_KEYNAME: basestring 
     1933    @cvar SQLQUERY_USERID_KEYNAME: key corresponding to string to be  
     1934    substituted into attribute query for user identifier e.g. 
     1935     
     1936    select attr from user_table where username = $userId 
     1937    ''' 
     1938     
     1939    str2Bool = staticmethod(_str2Bool) 
     1940     
     1941    SQLQUERY_USERID_KEYNAME = 'userId' 
     1942     
     1943    CONNECTION_STRING_OPTNAME = 'connectionString' 
     1944    ATTRIBUTE_SQLQUERY_OPTNAME = 'attributeSqlQuery' 
     1945    SAML_SUBJECT_SQLQUERY_OPTNAME = 'samlSubjectSqlQuery' 
     1946    SAML_ATTRIBUTE_SQLQUERIES_OPTNAME = 'samlAttributeSqlQueries' 
     1947    SAML_ATTRIBUTE_NAMES_OPTNAME = 'samlAttributeNames' 
     1948    SAML_VALID_REQUESTOR_DNS_OPTNAME = 'samlValidRequestorDNs' 
     1949    SAML_ASSERTION_LIFETIME_OPTNAME = 'samlAssertionLifetime' 
     1950     
     1951    __slots__ = ( 
     1952        CONNECTION_STRING_OPTNAME, 
     1953        ATTRIBUTE_SQLQUERY_OPTNAME, 
     1954        SAML_SUBJECT_SQLQUERY_OPTNAME, 
     1955        SAML_ATTRIBUTE_SQLQUERIES_OPTNAME, 
     1956        SAML_ATTRIBUTE_NAMES_OPTNAME, 
     1957        SAML_VALID_REQUESTOR_DNS_OPTNAME, 
     1958        SAML_ASSERTION_LIFETIME_OPTNAME, 
     1959        'samlAttributeMap' 
     1960    ) 
     1961    __PRIVATE_ATTR_PREFIX = '_SQLAlchemyAttributeInterface__' 
     1962    __slots__ += tuple([__PRIVATE_ATTR_PREFIX + i for i in __slots__]) 
     1963     
     1964    def __init__(self, **properties): 
     1965        '''Instantiate object taking in settings from the input 
     1966        properties''' 
     1967        log.debug('Initialising SQLAlchemyAttributeInterface instance ...') 
     1968         
     1969        if not sqlAlchemyInstalled: 
     1970            raise AttributeInterfaceConfigError("SQLAlchemy is not installed") 
     1971         
     1972        self.__connectionString = None 
     1973        self.__attributeSqlQuery = None 
     1974        self.__samlSubjectSqlQuery = None 
     1975        self.__samlAttributeSqlQueries = None 
     1976        self.__samlAttributeNames = None 
     1977        self.__samlValidRequestorDNs = None 
     1978        self.__samlAssertionLifetime = None 
     1979 
     1980        self.setProperties(**properties) 
     1981 
     1982    def setProperties(self, **properties): 
     1983        for name, val in properties.items(): 
     1984            setattr(self, name, val) 
     1985             
     1986    def _getSamlAssertionLifetime(self): 
     1987        return self.__samlAssertionLifetime 
     1988 
     1989    def _setSamlAssertionLifetime(self, value): 
     1990        if isinstance(value, timedelta): 
     1991            self.__samlAssertionLifetime = value 
     1992             
     1993        if isinstance(value, (float, int, long)): 
     1994            self.__samlAssertionLifetime = timedelta(seconds=value) 
     1995             
     1996        elif isinstance(value, basestring): 
     1997            self.__samlAssertionLifetime = timedelta(seconds=float(value)) 
     1998        else: 
     1999            raise TypeError('Expecting float, int, long, string or timedelta ' 
     2000                'type for "%s"; got %r' %  
     2001                (SQLAlchemyAttributeInterface.SAML_ASSERTION_LIFETIME_OPTNAME, 
     2002                 type(value))) 
     2003 
     2004    samlAssertionLifetime = property(_getSamlAssertionLifetime,  
     2005                                     _setSamlAssertionLifetime,  
     2006                                     doc="Time validity for SAML Assertion " 
     2007                                         "set in SAML Response returned from " 
     2008                                         "getAttributes") 
     2009 
     2010    def _getSamlSubjectSqlQuery(self): 
     2011        return self.__samlSubjectSqlQuery 
     2012 
     2013    def _setSamlSubjectSqlQuery(self, value): 
     2014        if not isinstance(value, basestring): 
     2015            raise TypeError('Expecting string type for "%s" attribute; got %r'% 
     2016                    (SQLAlchemyAttributeInterface.SAML_SUBJECT_SQLQUERY_OPTNAME, 
     2017                     type(value))) 
     2018             
     2019        self.__samlSubjectSqlQuery = value 
     2020 
     2021    samlSubjectSqlQuery = property(_getSamlSubjectSqlQuery,  
     2022                                   _setSamlSubjectSqlQuery,  
     2023                                   doc="SAML Subject SQL Query") 
     2024 
     2025    def _getSamlAttributeSqlQueries(self): 
     2026        return self.__samlAttributeSqlQueries 
     2027 
     2028    def _setSamlAttributeSqlQueries(self, value): 
     2029        if isinstance(value, basestring): 
     2030            # Allow for multiple queries split by a newline.  Empty and 
     2031            # commented lines are skipped 
     2032            self.__samlAttributeSqlQueries = [q for q in value.split(os.linesep) 
     2033                                              if q and not q.startswith('#')] 
     2034             
     2035        elif isinstance(value, (tuple, list)): 
     2036            for query in value: 
     2037                if not isinstance(query, basestring): 
     2038                    raise TypeError('Expecting string type for "%s" ' 
     2039                                    'attribute items; got %r' % 
     2040                (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE_SQLQUERIES_OPTNAME, 
     2041                 type(value))) 
     2042                     
     2043            self.__samlAttributeSqlQueries = value                  
     2044        else: 
     2045            raise TypeError('Expecting string, list or tuple type for "%s" ' 
     2046                'attribute; got %r' % 
     2047                (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE_SQLQUERIES_OPTNAME, 
     2048                 type(value))) 
     2049             
     2050 
     2051    samlAttributeSqlQueries = property(_getSamlAttributeSqlQueries,  
     2052                                       _setSamlAttributeSqlQueries,  
     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") 
     2061 
     2062    def _getSamlAttributeNames(self): 
     2063        return self.__samlAttributeNames 
     2064 
     2065    def _setSamlAttributeNames(self, value): 
     2066        if isinstance(value, basestring): 
     2067            self.__samlAttributeNames = [name for name in value.split()] 
     2068             
     2069        elif isinstance(value, (tuple, list)): 
     2070            for name in value: 
     2071                if not isinstance(name, basestring): 
     2072                    raise TypeError('Expecting string type for "%s" ' 
     2073                                    'attribute items; got %r' % 
     2074                    (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE_NAMES_OPTNAME, 
     2075                     type(value))) 
     2076                     
     2077            self.__samlAttributeNames = value 
     2078        else: 
     2079            raise TypeError('Expecting list/tuple or string type for "%s" ' 
     2080                    'attribute; got %r' % 
     2081                    (SQLAlchemyAttributeInterface.SAML_ATTRIBUTE_NAMES_OPTNAME, 
     2082                     type(value))) 
     2083             
     2084    samlAttributeNames = property(_getSamlAttributeNames,  
     2085                                  _setSamlAttributeNames,  
     2086                                  doc="Attribute names that the Attribute " 
     2087                                      "Authority supports retrieval of via " 
     2088                                      "its SAML Attribute query interface.  " 
     2089                                      "The order of these names is significant:" 
     2090                                      " the order must map directly to the " 
     2091                                      "results of the samlAttributeSqlQueries " 
     2092                                      "as retrieved by the " 
     2093                                      "_queryDbForSamlAttributes method") 
     2094 
     2095    def _getSamlValidRequestorDNs(self): 
     2096        return self.__samlValidRequestorDNs 
     2097 
     2098    def _setSamlValidRequestorDNs(self, value): 
     2099        if isinstance(value, basestring): 
     2100            self.__samlValidRequestorDNs = [X500DN.fromString(dn)  
     2101                                            for dn in value.split()] 
     2102        elif isinstance(value, (tuple, list)): 
     2103            self.__samlValidRequestorDNs = [X500DN.fromString(dn)  
     2104                                            for dn in value] 
     2105        else: 
     2106            raise TypeError('Expecting list/tuple or basestring type for "%s" ' 
     2107                'attribute; got %r' % 
     2108                (SQLAlchemyAttributeInterface.SAML_VALID_REQUESTOR_DNS_OPTNAME, 
     2109                 type(value))) 
     2110     
     2111    samlValidRequestorDNs = property(_getSamlValidRequestorDNs,  
     2112                                     _setSamlValidRequestorDNs,  
     2113                                     doc="list of certificate Distinguished " 
     2114                                         "Names referring to the client " 
     2115                                         "identities permitted to query the " 
     2116                                         "Attribute Authority via the SAML " 
     2117                                         "Attribute Query interface") 
     2118    def _getConnectionString(self): 
     2119        return self.__connectionString 
     2120 
     2121    def _setConnectionString(self, value): 
     2122        if not isinstance(value, basestring): 
     2123            raise TypeError('Expecting string type for "%s" attribute; got %r'% 
     2124                        (SQLAlchemyAttributeInterface.CONNECTION_STRING_OPTNAME, 
     2125                         type(value))) 
     2126        self.__connectionString = value 
     2127 
     2128    connectionString = property(fget=_getConnectionString,  
     2129                                fset=_setConnectionString,  
     2130                                doc="Database connection string") 
     2131 
     2132    def _getAttributeSqlQuery(self): 
     2133        return self.__attributeSqlQuery 
     2134 
     2135    def _setAttributeSqlQuery(self, value): 
     2136        if not isinstance(value, basestring): 
     2137            raise TypeError('Expecting string type for "%s" attribute; got %r'%  
     2138                    (SQLAlchemyAttributeInterface.ATTRIBUTE_SQLQUERY_OPTNAME, 
     2139                     type(value))) 
     2140        self.__attributeSqlQuery = value 
     2141 
     2142    attributeSqlQuery = property(fget=_getAttributeSqlQuery,  
     2143                                 fset=_setAttributeSqlQuery,  
     2144                                 doc="SQL Query for attribute query") 
     2145 
     2146    def getRoles(self, userId):      
     2147        """Return valid roles for the given userId 
     2148 
     2149        @type userId: basestring 
     2150        @param userId: user identity 
     2151        @rtype: list 
     2152        @return: list of roles for the given user 
     2153        """ 
     2154 
     2155        dbEngine = create_engine(self.connectionString) 
     2156        connection = dbEngine.connect() 
     2157         
     2158        try: 
     2159            queryInputs = { 
     2160                SQLAlchemyAttributeInterface.SQLQUERY_USERID_KEYNAME: 
     2161                userId 
     2162            } 
     2163            query = Template(self.attributeSqlQuery).substitute(queryInputs) 
     2164            result = connection.execute(query) 
     2165 
     2166        except exc.ProgrammingError: 
     2167            raise AttributeInterfaceRetrieveError("Error with SQL Syntax: %s" % 
     2168                                                  traceback.format_exc()) 
     2169        finally: 
     2170            connection.close() 
     2171 
     2172        try: 
     2173            attributes = [attr for attr in result][0][0] 
     2174         
     2175        except (IndexError, TypeError): 
     2176            raise AttributeInterfaceRetrieveError("Error with result set: %s" % 
     2177                                                  traceback.format_exc()) 
     2178         
     2179        log.debug('Attributes=%r retrieved for user=%r' % (attributes,  
     2180                                                           userId)) 
     2181         
     2182        return attributes 
     2183 
     2184    def getAttributes(self, attributeQuery, response): 
     2185        """Attribute Authority SAML AttributeQuery 
     2186         
     2187        @type attributeQuery: saml.saml2.core.AttributeQuery  
     2188        @param userId: query containing requested attributes 
     2189        @type: saml.saml2.core.Response 
     2190        @param: Response - add an assertion with the list of attributes  
     2191        for the given subject ID in the query or set an error Status code and 
     2192        message 
     2193        @raise AttributeInterfaceError: an error occured requesting  
     2194        attributes 
     2195        @raise AttributeReleaseDeniedError: Requestor was denied release of the 
     2196        requested attributes 
     2197        @raise AttributeNotKnownError: Requested attribute names are not known  
     2198        to this authority 
     2199        """ 
     2200        userId = attributeQuery.subject.nameID.value 
     2201        requestedAttributeNames = [attribute.name 
     2202                                   for attribute in attributeQuery.attributes] 
     2203         
     2204        requestorDN = X500DN.fromString(attributeQuery.issuer.value) 
     2205 
     2206        if not self._queryDbForSamlSubject(userId)(userId): 
     2207            raise UserIdNotKnown('Subject Id "%s" is not known to this ' 
     2208                                 'authority' % userId) 
     2209 
     2210        if requestorDN not in self.samlValidRequestorDNs: 
     2211            raise InvalidRequestorId('Requestor identity "%s" is invalid' % 
     2212                                     requestorDN) 
     2213 
     2214        unknownAttrNames = [attrName for attrName in requestedAttributeNames 
     2215                            if attrName not in self.samlAttributeNames] 
     2216 
     2217        if len(unknownAttrNames) > 0: 
     2218            raise AttributeNotKnownError("Unknown attributes requested: %r" % 
     2219                                         unknownAttrNames) 
     2220 
     2221        # Query the database for the supported attributes and return them 
     2222        # mapped to their attribute names as specified by the attributeNames 
     2223        # property 
     2224        attributeMap = self._queryDbForSamlAttributes(userId) 
     2225         
     2226        # Create a new assertion to hold the attributes to be returned 
     2227        assertion = Assertion() 
     2228 
     2229        assertion.version = SAMLVersion(SAMLVersion.VERSION_20) 
     2230        assertion.id = str(uuid4()) 
     2231        assertion.issueInstant = response.issueInstant 
     2232 
     2233        assertion.conditions = Conditions() 
     2234        assertion.conditions.notBefore = assertion.issueInstant 
     2235        assertion.conditions.notOnOrAfter = (assertion.conditions.notBefore +  
     2236                                timedelta(seconds=self.samlAssertionLifetime)) 
     2237 
     2238        assertion.subject = Subject() 
     2239        assertion.subject.nameID = NameID() 
     2240        assertion.subject.nameID.format = attributeQuery.subject.nameID.format 
     2241        assertion.subject.nameID.value = attributeQuery.subject.nameID.value 
     2242 
     2243        attributeStatement = AttributeStatement() 
     2244 
     2245        # Add test set of attributes 
     2246        for requestedAttribute in attributeQuery.attributes: 
     2247            attribute = Attribute() 
     2248            attribute.name = requestedAttribute.name 
     2249            attribute.nameFormat = requestedAttribute.nameFormat 
     2250 
     2251            if requestedAttribute.friendlyName is not None: 
     2252                attribute.friendlyName = requestedAttribute.friendlyName 
     2253 
     2254            if attribute.name in self.samlAttributeNames: 
     2255                attributeVals = attributeMap[attribute.name] 
     2256#                for val in badcAttributeVals: 
     2257#                    attribute.attributeValues.append(XSStringAttributeValue()) 
     2258#                    attribute.attributeValues[-1].value = val 
     2259# 
     2260#            elif attribute.name == CSVFileAttributeInterface.EMAILADDR_ATTR_NAME: 
     2261#                attribute.attributeValues.append(XSStringAttributeValue()) 
     2262#                attribute.attributeValues[-1].value = self.attributeMap[ 
     2263#                        userId][CSVFileAttributeInterface.EMAILADDR_ATTR_INDEX] 
     2264# 
     2265#            elif attribute.name == CSVFileAttributeInterface.FIRSTNAME_ATTR_NAME: 
     2266#                attribute.attributeValues.append(XSStringAttributeValue()) 
     2267#                attribute.attributeValues[-1].value = self.attributeMap[ 
     2268#                        userId][CSVFileAttributeInterface.FIRSTNAME_ATTR_INDEX] 
     2269# 
     2270#            elif attribute.name == CSVFileAttributeInterface.LASTNAME_ATTR_NAME: 
     2271#                attribute.attributeValues.append(XSStringAttributeValue()) 
     2272#                attribute.attributeValues[-1].value = self.attributeMap[ 
     2273#                        userId][CSVFileAttributeInterface.LASTNAME_ATTR_INDEX] 
     2274 
     2275            attributeStatement.attributes.append(attribute) 
     2276 
     2277        assertion.attributeStatements.append(attributeStatement) 
     2278        response.assertions.append(assertion) 
     2279         
     2280    def _queryDbForSamlSubject(self, userId):      
     2281        """Check a given SAML subject (user) is registered in the database. 
     2282        This method is called from the getAttributes() method 
     2283 
     2284        @type userId: basestring 
     2285        @param userId: user identity 
     2286        @rtype: bool 
     2287        @return: True/False is user registered? 
     2288        """ 
     2289        if self.samlSubjectSqlQuery is None: 
     2290            log.debug('No "self.samlSubjectSqlQuery" property has been set, ' 
     2291                      'skipping SAML subject query step') 
     2292            return True 
     2293         
     2294        dbEngine = create_engine(self.connectionString) 
     2295        connection = dbEngine.connect() 
     2296         
     2297        try: 
     2298            queryInputs = { 
     2299                SQLAlchemyAttributeInterface.SQLQUERY_USERID_KEYNAME: 
     2300                userId 
     2301            } 
     2302            query = Template(self.samlSubjectSqlQuery).substitute(queryInputs) 
     2303            result = connection.execute(query) 
     2304 
     2305        except exc.ProgrammingError: 
     2306            raise AttributeInterfaceRetrieveError("Error with SQL Syntax: %s" % 
     2307                                                  traceback.format_exc()) 
     2308        finally: 
     2309            connection.close() 
     2310 
     2311        try: 
     2312            found = [entry for entry in result][0][0] 
     2313         
     2314        except (IndexError, TypeError): 
     2315            raise AttributeInterfaceRetrieveError("Error with result set: %s" % 
     2316                                                  traceback.format_exc()) 
     2317         
     2318        log.debug('user=%r found=%r' % (username, found)) 
     2319         
     2320        return found 
     2321      
     2322    def _queryDbForSamlAttributes(self, userId):      
     2323        """Query the database in response to a SAML attribute query 
     2324         
     2325        This method is called from the getAttributes() method 
     2326 
     2327        @type userId: basestring 
     2328        @param userId: user identity 
     2329        @rtype: bool 
     2330        @return: True/False is user registered? 
     2331        """ 
     2332 
     2333        dbEngine = create_engine(self.connectionString) 
     2334        connection = dbEngine.connect() 
     2335         
     2336        attributes = ()  
     2337         
     2338        for queryTmpl in self.samlAttributeSqlQueries: 
     2339            try: 
     2340                queryInputs = { 
     2341                    SQLAlchemyAttributeInterface.SQLQUERY_USERID_KEYNAME: 
     2342                    userId 
     2343                } 
     2344                query = Template(queryTmpl).substitute(queryInputs) 
     2345                result = connection.execute(query) 
     2346     
     2347            except exc.ProgrammingError: 
     2348                raise AttributeInterfaceRetrieveError("Error with SQL Syntax: " 
     2349                                                      "%s" % 
     2350                                                      traceback.format_exc()) 
     2351            finally: 
     2352                connection.close() 
     2353 
     2354        try: 
     2355            found = [entry for entry in result][0][0] 
     2356         
     2357        except (IndexError, TypeError): 
     2358            raise AttributeInterfaceRetrieveError("Error with result set: %s" % 
     2359                                                  traceback.format_exc()) 
     2360         
     2361        log.debug('user=%r found=%r' % (username, found)) 
     2362         
     2363        attributeMap = dict(zip(self.samlAttributeNames, attributes)) 
     2364         
     2365        return attributeMap 
     2366       
     2367    def __getstate__(self): 
     2368        '''Explicit pickling required with __slots__''' 
     2369        return dict([(attrName, getattr(self, attrName)) \ 
     2370                      for attrName in SQLAlchemyAttributeInterface.__slots__]) 
     2371         
     2372    def __setstate__(self, attrDict): 
     2373        '''Enable pickling for use with beaker.session''' 
     2374        for attr, val in attrDict.items(): 
     2375            setattr(self, attr, val)             
     2376 
     2377         
     2378     
     2379         
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/__init__.py

    r5924 r5971  
    2424from ndg.security.test.unit.wsgi import PasteDeployAppServer 
    2525 
    26  
     26try: 
     27    from sqlalchemy import (create_engine, MetaData, Table, Column, Integer,  
     28                            String) 
     29    from sqlalchemy.ext.declarative import declarative_base 
     30    from sqlalchemy.orm import sessionmaker 
     31     
     32    sqlAlchemyInstalled = True 
     33except ImportError: 
     34    sqlAlchemyInstalled = False 
     35     
    2736class BaseTestCase(unittest.TestCase): 
    2837    '''Convenience base class from which other unit tests can extend.  Its 
     
    4554                                         "for unit tests") 
    4655     
     56    # Test database set-up 
     57    DB_FILENAME = 'user.db' 
     58    DB_CONNECTION_STR = 'sqlite:///%s' % DB_FILENAME 
     59    USERNAME = 'pjk' 
     60    OPENID_IDENTIFIER = 'philip.kershaw' 
     61    FIRSTNAME = 'Philip' 
     62    LASTNAME = 'Kershaw' 
     63    EMAILADDRESS = 'pjk@somewhere.ac.uk' 
     64    ATTRIBUTE_VALUES = ( 
     65        'urn:siteA:security:authz:1.0:attr:postdoc', 
     66        'urn:siteA:security:authz:1.0:attr:staff',  
     67        'urn:siteA:security:authz:1.0:attr:undergrad',  
     68        'urn:siteA:security:authz:1.0:attr:coapec', 
     69        'urn:siteA:security:authz:1.0:attr:rapid' 
     70    ) 
     71     
    4772    def __init__(self, *arg, **kw): 
    4873        if BaseTestCase.configDirEnvVarName not in os.environ: 
     
    104129                service.terminateThread() 
    105130             
     131    def _createDb(self): 
     132        """Create a test SQLite database with SQLAlchemy for use with unit  
     133        tests 
     134        """ 
     135        if not sqlAlchemyInstalled: 
     136            raise NotImplementedError("SQLAlchemy must be installed in order " 
     137                                      "for this method to be implemented") 
     138             
     139        db = create_engine(BaseTestCase.DB_CONNECTION_STR) 
     140         
     141        metadata = MetaData() 
     142        usersTable = Table('users', metadata, 
     143                           Column('id', Integer, primary_key=True), 
     144                           Column('username', String), 
     145                           Column('openid_identifier', String), 
     146                           Column('firstname', String), 
     147                           Column('lastname', String), 
     148                           Column('emailaddress', String)) 
     149         
     150        attributesTable = Table('attributes', metadata, 
     151                                Column('id', Integer, primary_key=True), 
     152                                Column('username', String), 
     153                                Column('attributename', String)) 
     154        metadata.create_all(db) 
     155         
     156        class User(declarative_base()): 
     157            __tablename__ = 'users' 
     158         
     159            id = Column(Integer, primary_key=True) 
     160            username = Column('username', String(40)) 
     161            openid_identifier = Column('openid_identifier', String(40)) 
     162            firstname = Column('firstname', String(40)) 
     163            lastname = Column('lastname', String(40)) 
     164            emailAddress = Column('emailaddress', String(40)) 
     165         
     166            def __init__(self, username, openid_identifier, firstname, 
     167                         lastname, emailaddress): 
     168                self.username = username 
     169                self.openid_identifier = openid_identifier 
     170                self.firstname = firstname 
     171                self.lastname = lastname 
     172                self.emailAddress = emailaddress 
     173         
     174        class Attribute(declarative_base()): 
     175            __tablename__ = 'attributes' 
     176         
     177            id = Column(Integer, primary_key=True) 
     178            username = Column('username', String(40)) 
     179            attributename = Column('attributename', String(40)) 
     180         
     181            def __init__(self, username, attributename): 
     182                self.username = username 
     183                self.attributename = attributename 
     184                 
     185        Session = sessionmaker(bind=db) 
     186        session = Session() 
     187         
     188        for attrName in BaseTestCase.ATTRIBUTE_VALUES: 
     189            session.add(Attribute(BaseTestCase.USERNAME, attrName)) 
     190             
     191        user = User(BaseTestCase.USERNAME,  
     192                    BaseTestCase.OPENID_IDENTIFIER, 
     193                    BaseTestCase.FIRSTNAME, 
     194                    BaseTestCase.LASTNAME, 
     195                    BaseTestCase.EMAILADDRESS) 
     196         
     197        session.add(user) 
     198        session.commit()  
     199 
     200 
    106201def _getParentDir(depth=0, path=dirname(__file__)): 
    107202    """ 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/attributeauthority/test_attributeauthority.py

    r5643 r5971  
    2525from ndg.security.test.unit import BaseTestCase 
    2626 
    27 from ndg.security.common.utils.configfileparsers import \ 
    28     CaseSensitiveConfigParser 
    29 from ndg.security.server.attributeauthority import AttributeAuthority, \ 
    30     AttributeAuthorityNoMatchingRoleInTrustedHosts 
     27from ndg.security.common.utils.configfileparsers import ( 
     28    CaseSensitiveConfigParser) 
     29from ndg.security.server.attributeauthority import (AttributeAuthority,  
     30    AttributeAuthorityNoMatchingRoleInTrustedHosts,  
     31    SQLAlchemyAttributeInterface) 
    3132 
    3233from ndg.security.common.AttCert import AttCert 
     
    238239                     "At least one Attribute Certificate request failed.  " 
    239240                     "Check the .msg files in this directory") 
    240                                          
     241 
     242     
     243class SQLAlchemyAttributeInterfaceTestCase(BaseTestCase): 
     244    def __init__(self, *arg, **kw): 
     245        super(SQLAlchemyAttributeInterfaceTestCase, self).__init__(*arg, **kw) 
     246        try: 
     247            self._createDb() 
     248        except NotImplementedError: 
     249            pass 
     250             
     251    def setUp(self): 
     252        pass 
     253         
     254    def test01(self): 
     255        attributeInterface = SQLAlchemyAttributeInterface() 
     256                                 
    241257if __name__ == "__main__": 
    242258    unittest.main() 
Note: See TracChangeset for help on using the changeset viewer.