Changeset 5504


Ignore:
Timestamp:
22/07/09 16:39:59 (10 years ago)
Author:
pjkersha
Message:

Progress with SAML Marshalling classes. These take a given SAML object type and convert it into an XML
representation (ElementTree used for this). Fred Lundh's custom ElementC14N class is essential because it correctly handles namespace prefixes.

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

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/saml/__init__.py

    r5503 r5504  
    2828# XML signature module based on M2Crypto, ZSI Canonicalization and DOM 
    2929from ndg.security.common.xmlsec.etree import XMLSecDoc, InvalidSignature 
    30  
    31 class AssertionMarshaller(object): 
    32     """ElementTree based marshalling of Assertion class into XML 
    33     """ 
    34     def __init__(self, assertion): 
    35         self._elem = Element() 
    36         self._root = None 
    37          
    38     def parse(self, source): 
    39         """Read in the XML from source 
    40         @type source: basestring/file 
    41         @param source: file path to XML file or file object 
    42         """ 
    43         elem = ElementTree.parse(source) 
    44         root = elem.getroot() 
    45          
    46         return root 
    47          
    48     def serialise(self): 
    49         return txt 
    50  
    51 class SAMLObject(XMLObject): 
     30from ndg.security.common.utils import QName, canonicalize 
     31 
     32class SAMLObject(object): 
    5233    pass 
    53  
    54 class QName(object): 
    55     def __init__(self, namespaceURI, localPart, prefix): 
    56         self.namespaceURI = namespaceURI 
    57         self.localPart = localPart 
    58         self.prefix = prefix 
    59  
    60     def _getPrefix(self): 
    61         return self.__prefix 
    62  
    63     def _setPrefix(self, value): 
    64         self.__prefix = value 
    65      
    66     prefix = property(_getPrefix, _setPrefix, None,  
    67                       "Prefix") 
    68  
    69     def _getLocalPart(self): 
    70         return self.__localPart 
    71      
    72     def _setLocalPart(self, value): 
    73         self.__localPart = value 
    74          
    75     localPart = property(_getLocalPart, _setLocalPart, None,  
    76                          "LocalPart") 
    77  
    78     def _getNamespaceURI(self): 
    79         return self.__namespaceURI 
    80  
    81     def _setNamespaceURI(self, value): 
    82         self.__namespaceURI = value 
    83    
    84     namespaceURI = property(_getNamespaceURI, _setNamespaceURI, None,  
    85                             "Namespace URI'") 
    86  
    8734 
    8835class XMLConstants(object): 
     
    316263     
    317264 
    318 class Assertion(XMLObject, XMLSecDoc): 
     265class Assertion(SAMLObject, XMLSecDoc): 
    319266    """SAML 2.0 Attribute Assertion for use with NERC DataGrid     
    320267    """     
     
    356303 
    357304        # Base class initialisation 
    358         XMLObject.__init__(self) 
     305        SAMLObject.__init__(self) 
    359306        XMLSecDoc.__init__(self, **xmlSecDocKw) 
    360307         
     
    380327        ''' 
    381328        if not isinstance(version, SAMLVersion): 
    382             raise TypeError("Expecting SAMLVersion type got: %r" % version) 
     329            raise TypeError("Expecting SAMLVersion type got: %r" %  
     330                            version.__class__) 
    383331         
    384332        self._version = version 
     
    388336                       doc="SAML Version of the assertion") 
    389337 
    390     def _get_issuerInstant(self): 
     338    def _get_issueInstant(self): 
    391339        '''Gets the issue instance of this assertion. 
    392340         
     
    394342        return self._issueInstant 
    395343     
    396     def _set_issuerInstant(self, issueInstant): 
     344    def _set_issueInstant(self, issueInstant): 
    397345        '''Sets the issue instance of this assertion. 
    398346         
    399347        @param newIssueInstance the issue instance of this assertion 
    400348        ''' 
     349        if not isinstance(issueInstant, datetime): 
     350            raise TypeError('Expecting "datetime" type for "issueInstant", ' 
     351                            'got %r' % issueInstant.__class__) 
     352             
    401353        self._issueInstant = issueInstant 
    402354         
    403     issuerInstant = property(fget=_get_issuerInstant,  
    404                              fset=_set_issuerInstant, 
    405                              doc="Issuer isntant of assertion") 
     355    issueInstant = property(fget=_get_issueInstant,  
     356                            fset=_set_issueInstant, 
     357                            doc="Issue instant of the assertion") 
    406358 
    407359    def _get_id(self): 
     
    417369        @param newID the ID of this assertion 
    418370        ''' 
     371        if not isinstance(_id, basestring): 
     372            raise TypeError('Expecting basestring derived type for "id", got ' 
     373                            '%r' % _id.__class__) 
    419374        self._id = _id 
    420375         
     
    425380        """Set issuer""" 
    426381        if not isinstance(issuer, basestring): 
    427             raise TypeError("issuer must be a string") 
     382            raise TypeError("issuer must be a string, got %r" %  
     383                            issuer.__class__) 
    428384         
    429385        self._issuer = issuer 
     
    441397        """Set subject string.""" 
    442398        if not isinstance(subject, basestring): 
    443             raise TypeError("subject must be a string") 
     399            raise TypeError("subject must be a string, got %r" %  
     400                            subject.__class__) 
    444401 
    445402        self._subject = subject 
     
    12551212         # no children 
    12561213         return None 
    1257       
     1214  
     1215 
     1216# TODO: refactor print helper 
    12581217from StringIO import StringIO 
    1259 def tostring(elem, **kw): 
     1218def elem2String(elem, **kw): 
     1219#    f = StringIO() 
     1220#    ElementC14N.write(ElementC14N.build_scoped_tree(elem),  
     1221#                      f,  
     1222#                      **kw) 
    12601223    f = StringIO() 
    1261     ElementC14N.write(ElementC14N.build_scoped_tree(elem),  
    1262                       f,  
    1263                       **kw) 
     1224    ElementC14N.write(ElementTree.ElementTree(element=elem), f) 
    12641225    return f.getvalue() 
    12651226 
    1266 if __name__ == "__main__": 
    1267     import pdb;pdb.set_trace() 
    1268     attrAss = Assertion() 
    1269     attrAss.issuerName = "http://badc.nerc.ac.uk" 
    1270     print attrAss.issuerName 
    1271     print attrAss 
     1227class AssertionMarshaller(object): 
     1228    issueInstantFmt = "%Y-%m-%dT%H:%M:%SZ" 
     1229     
     1230    @classmethod 
     1231    def issueInstantDatetime2Str(cls, dtIssueInstant): 
     1232        """Convert issue instant datetime to correct string type for output 
     1233        @type dtIssueInstant: datetime.datetime 
     1234        @param dtIssueInstant: issue instance as a datetime 
     1235        @rtype: basestring 
     1236        @return: issue instance as a string 
     1237        """ 
     1238        return dtIssueInstant.strftime(AssertionMarshaller.issueInstantFmt) 
     1239     
     1240class AssertionETreeMarshaller(AssertionMarshaller): 
     1241    """ElementTree based marshalling of Assertion class into XML 
     1242    """ 
     1243    def __init__(self): 
     1244        pass 
     1245 
     1246    def marshall(self, assertion): 
     1247        """Make a tree of a XML elements based on the assertion""" 
     1248        if not isinstance(assertion, Assertion): 
     1249            raise TypeError("Expecting %r type got: %r"%(Assertion, assertion)) 
     1250         
     1251        issueInstant = AssertionETreeMarshaller.issueInstantDatetime2Str( 
     1252                                                        assertion.issueInstant) 
     1253        attrib = { 
     1254            Assertion.ID_ATTRIB_NAME: assertion.id, 
     1255            Assertion.ISSUE_INSTANT_ATTRIB_NAME: issueInstant, 
     1256             
     1257            # Nb. Version is a SAMLVersion instance and requires explicit cast 
     1258            Assertion.VERSION_ATTRIB_NAME: str(assertion.version) 
     1259        } 
     1260        assertionElem=ElementTree.Element(str(Assertion.DEFAULT_ELEMENT_NAME),  
     1261                                          **attrib) 
     1262         
     1263        assertionElem.set("xmlns:%s" % Assertion.DEFAULT_ELEMENT_NAME.prefix,  
     1264                          Assertion.DEFAULT_ELEMENT_NAME.namespaceURI) 
     1265         
     1266        self.marshallAttributes(assertion, assertionElem) 
     1267         
     1268        print canonicalize(assertionElem) 
     1269        return assertionElem 
     1270 
     1271    def marshallAttributes(self, assertion, assertionElem): 
     1272        attributeStatementETreeMarshaller = AttributeStatementETreeMarshaller() 
     1273         
     1274        for attributeStatement in assertion.attributeStatements: 
     1275            attributeStatementElem = attributeStatementETreeMarshaller( 
     1276                                                        attributeStatement) 
     1277            assertionElem.append(attributeStatementElem) 
     1278             
     1279 
     1280class AttributeStatementETreeMarshaller(object): 
     1281    """Marshal AttributeStatement object into an ElementTree XML  
     1282    representation""" 
     1283    def marshall(self, attributeStatement, makeNsDeclaration=False, **attrib): 
     1284        if not isinstance(attributeStatement, AttributeStatement): 
     1285            raise TypeError("Expecting %r type got: %r" % (AttributeStatement,  
     1286                                                           attributeStatement)) 
     1287             
     1288        attributeStatementElem = ElementTree.Element( 
     1289                                str(AttributeStatement.DEFAULT_ELEMENT_NAME),  
     1290                                **attrib) 
     1291        if makeNsDeclaration: 
     1292            attributeStatementElem.set( 
     1293                "xmlns:%s" % AttributeStatement.DEFAULT_ELEMENT_NAME.prefix,  
     1294                AttributeStatement.DEFAULT_ELEMENT_NAME.namespaceURI) 
     1295         
     1296        return attributeStatementElem 
     1297 
     1298    def marshallAttributes(self, attributeStatement, attributeStatement): 
     1299        for attribute in attributeStatement.attributes: 
     1300            attributeElem = attributeStatementETreeMarshaller( 
     1301                                                        attributeStatement) 
     1302            assertionElem.append(attributeStatementElem) 
     1303 
     1304class AttributeETreeMarshaller(object): 
     1305    """Marshal Attribute object into an ElementTree XML representation"""  
     1306 
     1307class _AssertionTmp:         
     1308    def parse(self, source): 
     1309        """Read in the XML from source 
     1310        @type source: basestring/file 
     1311        @param source: file path to XML file or file object 
     1312        """ 
     1313        elem = ElementTree.parse(source) 
     1314        root = elem.getroot() 
     1315         
     1316        return root 
     1317         
     1318    def serialise(self): 
     1319        return txt 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/utils/__init__.py

    r5395 r5504  
    99__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1010__revision__ = '$Id: $' 
     11try: # python 2.5 
     12    from xml.etree import cElementTree as ElementTree 
     13except ImportError: 
     14    # if you've installed it yourself it comes this way 
     15    import cElementTree as ElementTree 
     16 
     17# Fred Lundh's customisation for C14N functionality - egg available from 
     18# http://ndg.nerc.ac.uk/dist site 
     19c14nWarning = ("Custom ElementC14N package is not installed, canonicalize " 
     20               "function is disabled") 
     21try: 
     22    from elementtree import ElementC14N 
     23    elementC14nNotInstalled = False 
     24except ImportError: 
     25    elementC14nNotInstalled = True 
     26    import warnings 
     27    warnings.warn(c14nWarning) 
     28     
     29from cStringIO import StringIO 
    1130 
    1231# ElementTree helpers   
    1332getNs = lambda elem: elem.tag.split('}')[0][1:] 
    1433getLocalName = lambda elem: elem.tag.rsplit('}',1)[-1] 
     34 
     35class QName(ElementTree.QName): 
     36    def __init__(self, namespaceURI, tag=None, prefix=None): 
     37        ElementTree.QName.__init__(self, namespaceURI, tag=tag) 
     38         
     39        if tag: 
     40            self.namespaceURI = namespaceURI 
     41            self.localPart = tag 
     42        else: 
     43            self.namespaceURI = getNs(self.text) 
     44            self.localPart = getLocalName(self.text) 
     45             
     46        self.prefix = prefix 
     47 
     48    def _getPrefix(self): 
     49        return self.__prefix 
     50 
     51    def _setPrefix(self, value): 
     52        self.__prefix = value 
     53     
     54    prefix = property(_getPrefix, _setPrefix, None, "Prefix") 
     55 
     56    def _getLocalPart(self): 
     57        return self.__localPart 
     58     
     59    def _setLocalPart(self, value): 
     60        self.__localPart = value 
     61         
     62    localPart = property(_getLocalPart, _setLocalPart, None, "LocalPart") 
     63 
     64    def _getNamespaceURI(self): 
     65        return self.__namespaceURI 
     66 
     67    def _setNamespaceURI(self, value): 
     68        self.__namespaceURI = value 
     69   
     70    namespaceURI = property(_getNamespaceURI, _setNamespaceURI, None,  
     71                            "Namespace URI'") 
     72 
     73def canonicalize(elem, **kw): 
     74    '''ElementTree based Canonicalization - See ElementC14N for keyword 
     75    info.  Also useful for pretty printing XML 
     76    @type elem: ElementTree.Element 
     77    @param elem: element to be canonicalized 
     78    @rtype: basestring 
     79    @return: canonicalised output 
     80    ''' 
     81    if elementC14nNotInstalled: 
     82        raise NotImplementedError(c14nWarning) 
     83     
     84    f = StringIO() 
     85    ElementC14N.write(ElementC14N.build_scoped_tree(elem), f, **kw) 
     86    return f.getvalue() 
    1587 
    1688 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/unit/attributeauthority/saml/test_samlinterface.py

    r5503 r5504  
    1313from ndg.security.test.unit import BaseTestCase 
    1414from ndg.security.common.saml import Attribute, AttributeValue, \ 
    15     AttributeStatement, Assertion, SAMLVersion, XSGroupRole 
     15    AttributeStatement, Assertion, SAMLVersion, XSGroupRole, \ 
     16    AssertionETreeMarshaller 
    1617from datetime import datetime 
    1718import base64  
    1819import os 
     20from uuid import uuid4 
    1921 
    2022class Request(object): 
     
    3537        samlUtil.firstName = "Philip" 
    3638        samlUtil.lastName = "Kershaw" 
    37         samlUtil.groupRoleList = [('badc', 'admin')] 
     39        samlUtil.groupRoleList = [ 
     40            ('urn:badc:security:authz:1.0:attr:org:id:badc',  
     41             'urn:badc:security:authz:1.0:attr:staff') 
     42        ] 
    3843        assertion = samlUtil.buildAssertion() 
     44        marshaller = AssertionETreeMarshaller() 
     45        assertionElem = marshaller.marshall(assertion) 
    3946 
    4047 
     
    5966        assertion = Assertion() 
    6067        assertion.version = SAMLVersion(SAMLVersion.VERSION_20) 
    61         assertion.id = base64.b64encode(os.urandom(32))[:32] 
    62         assertion.issueInstant = str(datetime.utcnow()) 
     68        assertion.id = str(uuid4()) 
     69        assertion.issueInstant = datetime.utcnow() 
    6370 
    6471        attributeStatement = AttributeStatement() 
Note: See TracChangeset for help on using the changeset viewer.