Changeset 5929


Ignore:
Timestamp:
02/11/09 15:46:36 (10 years ago)
Author:
pjkersha
Message:

Working unit tests for MyProxy? SAML Attribute assertion callout. TODO: add console script entry point.

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

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/myproxy/certificate_extapp/saml_attribute_assertion.py

    r5924 r5929  
    1313log = logging.getLogger(__name__) 
    1414 
     15import traceback 
    1516from datetime import datetime 
    1617from uuid import uuid4 
     18from string import Template 
     19 
     20from sqlalchemy import create_engine, exc 
     21 
     22try: # >= python 2.5 
     23    from xml.etree import ElementTree 
     24except ImportError: 
     25    import ElementTree 
    1726 
    1827from saml.common.xml import SAMLConstants 
     
    2231    XSStringAttributeValue,  
    2332    StatusCode) 
    24 from saml.xml.etree import ResponseElementTree 
     33from saml.xml.etree import AssertionElementTree 
    2534    
    2635from ndg.security.common.saml.bindings import SOAPBinding as SamlSoapBinding 
    2736from ndg.security.common.X509 import X500DN 
    28  
    29  
     37from ndg.security.server.wsgi.openid.provider import IdentityMapping 
     38 
     39 
     40class SamlAssertionMyProxyCertExtAppError(Exception): 
     41    """Base class for SamlAssertionMyProxyCertExtApp class exceptions""" 
     42     
     43     
     44class SamlAssertionMyProxyCertExtAppConfigError( 
     45                                        SamlAssertionMyProxyCertExtAppError): 
     46    """Configuration fault for SamlAssertionMyProxyCertExtApp instance""" 
     47 
     48 
     49class SamlAssertionMyProxyCertExtAppRetrieveError( 
     50                                        SamlAssertionMyProxyCertExtAppError): 
     51    """Error retrieving results from user database or attribute authority""" 
     52     
     53 
     54class SamlAssertionMyProxyCertExtAppSqlError( 
     55                                        SamlAssertionMyProxyCertExtAppError):    
     56    """Error with SQL query syntax""" 
     57     
     58     
    3059class SamlAssertionMyProxyCertExtApp(object): 
    3160    """Application to create a X.509 certificate extension containing a SAML 
     
    5180        ("urn:esg:email:address", "emailAddress", XSSTRING_NS), 
    5281    ) 
     82    ESG_NAME_ID_FORMAT = "urn:esg:openid" 
     83     
     84    CONNECTION_STRING_OPTNAME = 'connectionString' 
     85    OPENID_SQLQUERY_OPTNAME = 'openIdSqlQuery' 
     86    OPENID_IDENTITY_URI_TMPL_OPTNAME = 'identityUriTemplate' 
    5387     
    5488    __slots__ = ( 
    55        '_SamlAssertionMyProxyCertExtApp__attributeAuthorityURI', 
    56        '_SamlAssertionMyProxyCertExtApp__userOpenID', 
    57        '_SamlAssertionMyProxyCertExtApp__issuerDN', 
    58        '_SamlAssertionMyProxyCertExtApp__attributeDescr', 
    5989       'attributeAuthorityURI', 
    6090       'userOpenID', 
    6191       'issuerDN', 
    62        'attributeDescr' 
     92       'attributeDescr', 
     93       CONNECTION_STRING_OPTNAME, 
     94       OPENID_SQLQUERY_OPTNAME, 
     95       OPENID_IDENTITY_URI_TMPL_OPTNAME 
    6396    ) 
     97    __PRIVATE_ATTR_PREFIX = '_SamlAssertionMyProxyCertExtApp__' 
     98    __slots__ += tuple([__PRIVATE_ATTR_PREFIX + i for i in __slots__]) 
    6499     
    65100    def __init__(self): 
     
    67102        self.__userOpenID = None 
    68103        self.__issuerDN = None 
    69          
    70         # Use property here in case DEFAULT_ATTR_DESCR has been altered 
     104        self.__connectionString = None 
     105        self.__openIdSqlQuery = None 
     106        self.__identityUriTemplate = None  
     107                
     108        # Use property here as a safeguard in case DEFAULT_ATTR_DESCR has been 
     109        # altered 
    71110        self.attributeDescr = SamlAssertionMyProxyCertExtApp.DEFAULT_ATTR_DESCR 
     111 
     112    def __call__(self, username): 
     113        """Main method - create SAML assertion by querying the user's OpenID 
     114        identifier from the user database and using this to query the  
     115        Attribute Authority for attributes 
     116        """ 
     117        identifier = self.queryOpenId(username) 
     118        self.userOpenID = IdentityMapping.userIdentifier2IdentityURI( 
     119                                                    self.identityUriTemplate,  
     120                                                    identifier) 
     121         
     122        response = self.attributeQuery() 
     123         
     124        try: 
     125            assertionStr = self.serialiseAssertion(response.assertions[0]) 
     126             
     127        except (IndexError, TypeError): 
     128            raise SamlAssertionMyProxyCertExtAppRetrieveError("Error accessing " 
     129                    "assertion from Attribute Authority SAML response: %s" % 
     130                    traceback.format_exc()) 
     131             
     132        return assertionStr 
    72133 
    73134    def _getAttributeDescr(self): 
     
    142203                            "Query to Attribute Authority") 
    143204 
     205    def _getConnectionString(self): 
     206        return self.__connectionString 
     207 
     208    def _setConnectionString(self, value): 
     209        if not isinstance(value, basestring): 
     210            raise TypeError('Expecting string type for "%s" attribute; got %r'% 
     211                    (SamlAssertionMyProxyCertExtApp.CONNECTION_STRING_OPTNAME, 
     212                     type(value))) 
     213        self.__connectionString = value 
     214 
     215    connectionString = property(fget=_getConnectionString,  
     216                                fset=_setConnectionString,  
     217                                doc="Database connection string") 
     218 
     219    def _getOpenIdSqlQuery(self): 
     220        return self.__openIdSqlQuery 
     221 
     222    def _setOpenIdSqlQuery(self, value): 
     223        if not isinstance(value, basestring): 
     224            raise TypeError('Expecting string type for "%s" attribute; got %r'%  
     225                        (SamlAssertionMyProxyCertExtApp.OPENID_SQLQUERY_OPTNAME, 
     226                         type(value))) 
     227        self.__openIdSqlQuery = value 
     228 
     229    openIdSqlQuery = property(fget=_getOpenIdSqlQuery,  
     230                        fset=_setOpenIdSqlQuery,  
     231                        doc="SQL Query for authentication request") 
     232 
     233    def _getIdentityUriTemplate(self): 
     234        return self.__identityUriTemplate 
     235 
     236    def _setIdentityUriTemplate(self, value): 
     237        if not isinstance(value, basestring): 
     238            raise TypeError('Expecting string type for "%s" attribute; got %r'%  
     239            (SamlAssertionMyProxyCertExtApp.OPENID_IDENTITY_URI_TMPL_OPTNAME, 
     240             type(value))) 
     241        self.__identityUriTemplate = value 
     242 
     243    identityUriTemplate = property(_getIdentityUriTemplate,  
     244                                   _setIdentityUriTemplate,  
     245                                   doc="Identity URI template string - sets " 
     246                                       "the common component of user's " 
     247                                       "identity URI.  It should contain the " 
     248                                       "${userIdentifier} template " 
     249                                       "substitution parameter") 
     250         
    144251    def __getstate__(self): 
    145252        '''Specific implementation needed with __slots__''' 
     
    151258        for attr, val in attrDict.items(): 
    152259            setattr(self, attr, val) 
    153                      
     260     
     261    def serialiseAssertion(self, assertion): 
     262        """Convert SAML assertion object into a string""" 
     263        samlAssertionElem = AssertionElementTree.toXML(assertion) 
     264        return ElementTree.tostring(samlAssertionElem) 
     265         
    154266    def attributeQuery(self): 
    155267        """Query an Attribute Authority to retrieve an assertion for the  
     
    168280        attributeQuery.subject = Subject()   
    169281        attributeQuery.subject.nameID = NameID() 
    170         attributeQuery.subject.nameID.format = "urn:esg:openid" 
     282        attributeQuery.subject.nameID.format = \ 
     283                            SamlAssertionMyProxyCertExtApp.ESG_NAME_ID_FORMAT 
    171284        attributeQuery.subject.nameID.value = self.userOpenID 
    172285                   
     
    195308        assert(response.assertions[-1].conditions.notBefore < now)  
    196309        assert(response.assertions[-1].conditions.notOnOrAfter > now) 
    197           
    198         samlResponseElem = ResponseElementTree.toXML(response) 
    199          
    200         return 
     310         
     311        return response 
     312     
     313    def queryOpenId(self, username): 
     314        """Given a username, query for user OpenID identifier from the user  
     315        database 
     316 
     317        @type username: basestring 
     318        @param username: username 
     319        @rtype: basestring 
     320        @return: the OpenID identifier corresponding to the input username 
     321        """ 
     322 
     323        try: 
     324            dbEngine = create_engine(self.connectionString) 
     325        except ImportError, e: 
     326            raise SamlAssertionMyProxyCertExtAppConfigError("Missing database " 
     327                                                            "engine for " 
     328                                                            "SQLAlchemy: %s" %  
     329                                                            e) 
     330        connection = dbEngine.connect() 
     331         
     332        try: 
     333            queryInputs = dict(username=username) 
     334            query = Template(self.openIdSqlQuery).substitute(queryInputs) 
     335            result = connection.execute(query) 
     336 
     337        except exc.ProgrammingError: 
     338            raise SamlAssertionMyProxyCertExtAppSqlError( 
     339                                                "Error with SQL Syntax: %s" % 
     340                                                traceback.format_exc()) 
     341        finally: 
     342            connection.close() 
     343 
     344        try: 
     345            identifier = [r for r in result][0][0] 
     346         
     347        except Exception: 
     348            raise SamlAssertionMyProxyCertExtAppRetrieveError( 
     349                                                "Error with result set: %s" % 
     350                                                traceback.format_exc()) 
     351         
     352        log.debug('Query succeeded for user %r' % username) 
     353        return identifier 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/authninterface/__init__.py

    r5791 r5929  
    7474    Derive from this class to define the authentication interface for users 
    7575    logging into the OpenID Provider''' 
     76    __slots__ = () 
    7677     
    7778    def __init__(self, **prop): 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/axinterface/__init__.py

    r5870 r5929  
    2828    """Interface class for OpenID Provider to respond to Attribute Exchange 
    2929    Requests from a Relying Party""" 
     30    __slots__ = () 
    3031     
    3132    userIdentifier2IdentityURI = IdentityMapping.userIdentifier2IdentityURI 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/myproxy/certificate_extapp/test_saml_attribute_assertion.py

    r5924 r5929  
    1313import logging 
    1414logging.basicConfig(level=logging.DEBUG) 
     15import os 
     16from string import Template 
     17 
     18from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String 
     19from sqlalchemy.ext.declarative import declarative_base 
     20from sqlalchemy.orm import sessionmaker 
    1521 
    1622from ndg.security.test.unit import BaseTestCase 
    1723from ndg.security.server.myproxy.certificate_extapp.saml_attribute_assertion \ 
    1824    import SamlAssertionMyProxyCertExtApp 
    19      
     25  
     26from sqlalchemy.ext.declarative import declarative_base 
     27 
    2028 
    2129class SamlAssertionMyProxyCertExtAppTestCase(BaseTestCase): 
     30    THIS_DIR = os.path.dirname(__file__) 
     31    USERNAME = 'pjk' 
     32    OPENID_IDENTIFIER = 'philip.kershaw' 
     33    OPENID_TMPL = "https://openid.localhost/${userIdentifier}" 
     34    OPENID = Template(OPENID_TMPL).substitute( 
     35                                        dict(userIdentifier=OPENID_IDENTIFIER)) 
     36     
     37    DB_FILENAME = 'user.db' 
     38    DB_CONNECTION_STR = 'sqlite:///%s' % DB_FILENAME 
     39     
    2240    def __init__(self, *arg, **kw): 
    2341        super(SamlAssertionMyProxyCertExtAppTestCase, self).__init__(*arg,  
    2442                                                                     **kw)             
    2543        self.startSiteAAttributeAuthority() 
     44        if not os.path.isfile(os.path.join( 
     45                        SamlAssertionMyProxyCertExtAppTestCase.THIS_DIR, 
     46                        SamlAssertionMyProxyCertExtAppTestCase.DB_FILENAME)): 
     47            self._createDb() 
    2648         
    27     def test01(self): 
     49    def _createDb(self): 
     50        db = create_engine( 
     51                    SamlAssertionMyProxyCertExtAppTestCase.DB_CONNECTION_STR) 
     52         
     53        metadata = MetaData() 
     54        table = Table('users', metadata, 
     55                      Column('id', Integer, primary_key=True), 
     56                      Column('username', String), 
     57                      Column('openid_identifier', String)) 
     58        metadata.create_all(db) 
     59         
     60        class User(declarative_base()): 
     61            __tablename__ = 'users' 
     62         
     63            id = Column(Integer, primary_key=True) 
     64            username = Column('username', String(40)) 
     65            openid_identifier = Column('openid_identifier', String(40)) 
     66         
     67            def __init__(self, username, openid_identifier): 
     68                self.username = username 
     69                self.openid_identifier = openid_identifier 
     70         
     71        user = User(SamlAssertionMyProxyCertExtAppTestCase.USERNAME,  
     72                    SamlAssertionMyProxyCertExtAppTestCase.OPENID_IDENTIFIER) 
     73         
     74        Session = sessionmaker(bind=db) 
     75        session = Session() 
     76        session.add(user) 
     77        session.commit() 
     78         
     79    def test01DbQuery(self): 
     80        myProxyCertExtApp = SamlAssertionMyProxyCertExtApp() 
     81        myProxyCertExtApp.connectionString = \ 
     82                    SamlAssertionMyProxyCertExtAppTestCase.DB_CONNECTION_STR 
     83                     
     84        myProxyCertExtApp.openIdSqlQuery = ( 
     85                            "select openid_identifier from " 
     86                            "users where username = '%s'" % 
     87                            SamlAssertionMyProxyCertExtAppTestCase.USERNAME) 
     88         
     89        identifier = myProxyCertExtApp.queryOpenId( 
     90                                SamlAssertionMyProxyCertExtAppTestCase.USERNAME) 
     91        self.assert_(identifier ==  
     92                     SamlAssertionMyProxyCertExtAppTestCase.OPENID_IDENTIFIER) 
     93         
     94    def test02AttributeQuery(self): 
    2895        myProxyCertExtApp = SamlAssertionMyProxyCertExtApp() 
    2996        myProxyCertExtApp.attributeAuthorityURI = ('http://localhost:%d' 
     
    3299        ) 
    33100        myProxyCertExtApp.issuerDN = "/O=Site A/CN=Authorisation Service" 
    34         myProxyCertExtApp.userOpenID = "https://openid.localhost/philip.kershaw" 
     101        myProxyCertExtApp.userOpenID = \ 
     102                                SamlAssertionMyProxyCertExtAppTestCase.OPENID 
     103                                 
    35104        assertion = myProxyCertExtApp.attributeQuery() 
    36105        print(assertion) 
     106         
     107    def test03End2End(self): 
     108        myProxyCertExtApp = SamlAssertionMyProxyCertExtApp() 
     109         
     110        myProxyCertExtApp.connectionString = \ 
     111                    SamlAssertionMyProxyCertExtAppTestCase.DB_CONNECTION_STR 
     112                     
     113        myProxyCertExtApp.openIdSqlQuery = ( 
     114                            "select openid_identifier from " 
     115                            "users where username = '%s'" % 
     116                            SamlAssertionMyProxyCertExtAppTestCase.USERNAME) 
     117         
     118        myProxyCertExtApp.identityUriTemplate = \ 
     119                            SamlAssertionMyProxyCertExtAppTestCase.OPENID_TMPL 
     120                             
     121        myProxyCertExtApp.attributeAuthorityURI = ('http://localhost:%d' 
     122                                                   '/AttributeAuthority/saml' %  
     123        SamlAssertionMyProxyCertExtAppTestCase.SITEA_ATTRIBUTEAUTHORITY_PORTNUM 
     124        ) 
     125        myProxyCertExtApp.issuerDN = "/O=Site A/CN=Authorisation Service" 
     126         
     127        assertion = myProxyCertExtApp( 
     128                                SamlAssertionMyProxyCertExtAppTestCase.USERNAME) 
     129        self.assert_(assertion) 
     130        print(assertion) 
     131         
Note: See TracChangeset for help on using the changeset viewer.