Changeset 5554


Ignore:
Timestamp:
04/08/09 12:56:47 (10 years ago)
Author:
pjkersha
Message:
  • Started adding ElementTree based parsers for SAML classes in ndg.security.common.saml.xml.etree.
  • ndg.security.common.utils.prettyPrint needs a bug fix for namespace declarations
Location:
TI12-security/trunk/python
Files:
5 edited

Legend:

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

    r5538 r5554  
    4848    VERSION_11 = (1, 1) 
    4949    VERSION_20 = (2, 0) 
     50    KNOWN_VERSIONS = (VERSION_10, VERSION_11, VERSION_20) 
    5051     
    5152    def __init__(self, version): 
    52         self.__version = version 
     53        if isinstance(version, basestring): 
     54            self.__version = SAMLVersion.valueOf(version) 
     55        elif isinstance(version, (tuple, list)): 
     56            self.__version = tuple(version) 
     57        else: 
     58            raise TypeError("Expecting string, tuple or list type for SAML " 
     59                            "version initialiser; got %r" % version) 
    5360     
    5461    def __str__(self): 
    5562        return ".".join([str(i) for i in self.__version]) 
    5663     
     64    def __eq__(self, version): 
     65        """Test for equality against an input version string, tuple or list""" 
     66                 
     67        if isinstance(version, basestring): 
     68            return self.__version == SAMLVersion.valueOf(version) 
     69        elif isinstance(version, (tuple, list)): 
     70            return self.__version == tuple(version) 
     71        else: 
     72            raise TypeError("Expecting string, tuple or list type for SAML " 
     73                            "version comparison; got %r" % version) 
     74             
     75    def __ne__(self, version): 
     76        return self.__eq__(version) 
     77     
    5778    @staticmethod 
    5879    def valueOf(version): 
     80        """Parse input string into version tuple 
     81        @type version: version 
     82        @param version: SAML version 
     83        @rtype: tuple 
     84        @return: SAML version tuple""" 
    5985        return tuple(version.split(".")) 
    6086     
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/saml/xml/__init__.py

    r5538 r5554  
    2727__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    2828__revision__ = "$Id$" 
     29from datetime import datetime 
     30try: 
     31    from datetime import strptime 
     32except ImportError: 
     33    # Allow for Python < 2.5 
     34    from time import strptime as _strptime 
     35    strptime = lambda datetimeStr, format: datetime(*(_strptime(datetimeStr,  
     36                                                                format)[0:6])) 
    2937 
    3038class XMLConstants(object): 
     
    132140    #  Liberty PAOS QName prefix. 
    133141    PAOS_PREFIX = "paos" 
    134  
    135142     
    136143    #    SAML 1.X 
     
    185192        "urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" 
    186193     
    187      
    188194    #    SAML 2.0 
    189195     
     
    298304    SAML2_SOAP11_BINDING_URI = "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" 
    299305 
     306class XMLObjectError(Exception): 
     307    pass 
     308 
     309class XMLObjectParsingError(Exception): 
     310    pass 
    300311 
    301312class XMLObject(object): 
    302313    """Abstract base class for XML representations of SAML objects""" 
    303314     
    304     def create(self, samlObject, makeNsDeclaration=True): 
    305         """Create an XML representation from the input SAML object""" 
     315    def create(self, samlObject): 
     316        """Create an XML representation from the input SAML object 
     317        @type samlObject: SAMLObject 
     318        param samlObject: SAML object to render into XML 
     319        """ 
    306320        raise NotImplementedError() 
    307321 
    308     def parse(self, source): 
     322    def parse(self, elem): 
    309323        """Parse into XML representation 
    310         @type source: basestring/file 
    311         @param source: file object or string content containing XML 
     324        @type elem: object 
     325        @param elem: XML object - type depends on XML class representation 
     326        @rtype: SAMLObject 
     327        @return: equivalent SAML object 
     328        @raise XMLObjectParsingError: error parsing content into SAML  
     329        representation 
    312330        """ 
    313331        raise NotImplementedError() 
     
    333351        @return: issue instance as a string 
    334352        """ 
     353        if not isinstance(dtIssueInstant, datetime): 
     354            raise TypeError("Expecting datetime type for string conversion, " 
     355                            "got %r" % dtIssueInstant) 
     356             
    335357        return dtIssueInstant.strftime(IssueInstantXMLObject.issueInstantFmt) 
    336358 
     359    @classmethod 
     360    def str2Datetime(cls, issueInstant): 
     361        """Convert issue instant string to datetime type 
     362        @type issueInstant: basestring 
     363        @param issueInstant: issue instance as a string 
     364        @rtype: datetime.datetime 
     365        @return: issue instance as a datetime 
     366        """ 
     367        if not isinstance(issueInstant, basestring): 
     368            raise TypeError("Expecting basestring derived type for string " 
     369                            "conversion, got %r" % issueInstant) 
     370             
     371        return datetime.strptime(issueInstant,  
     372                                 IssueInstantXMLObject.issueInstantFmt) 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/saml/xml/etree.py

    r5538 r5554  
    3939from ndg.security.common.saml import SAMLObject, Assertion, Attribute, \ 
    4040    AttributeStatement, AttributeValue, XSStringAttributeValue, \ 
    41     XSGroupRoleAttributeValue, AttributeQuery, Subject, NameID, Issuer 
     41    XSGroupRoleAttributeValue, AttributeQuery, Subject, NameID, Issuer, \ 
     42    SAMLVersion 
    4243     
    4344from ndg.security.common.saml.xml import XMLObject, IssueInstantXMLObject, \ 
    44     SAMLConstants 
    45  
    46  
    47 class ETreeObject(XMLObject): 
     45    XMLObjectParsingError, SAMLConstants 
     46 
     47from ndg.security.common.utils import getLocalName, prettyPrint 
     48 
     49class SAMLElementTree(XMLObject): 
    4850    """Implement methods generic to all ElementTree SAML object representations 
    49     """ 
    50     def __init__(self): 
    51         self._elem = None 
    52          
    53     def parse(self, source): 
    54         """Read in the XML from source 
    55         @type source: basestring/file 
    56         @param source: file path to XML file or file object 
    57         """ 
    58         tree = ElementTree.parse(source) 
    59         self._elem = tree.getroot() 
    60          
    61         return self._elem 
    62 #     
    63 #    def serialize(self): 
    64 #        """Serialise element tree into string""" 
    65 #        return canonicalize(self._elem) 
    66      
    67     def serialize(self): 
     51    """        
     52#    def parse(self, source): 
     53#        """Read in the XML from source 
     54#        @type source: basestring/file 
     55#        @param source: file path to XML file or file object 
     56#        """ 
     57#        tree = ElementTree.parse(source) 
     58#        self.__elem = tree.getroot() 
     59#         
     60#        return self.__elem 
     61#    
     62    @staticmethod      
     63    def serialize(elem): 
    6864        """Serialise element tree into string""" 
    69         return cElementTree.tostring(self._elem) 
     65        return cElementTree.tostring(elem) 
    7066    
    71     def prettyPrint(self): 
     67    @staticmethod 
     68    def prettyPrint(elem): 
    7269        """Basic pretty printing separating each element on to a new line""" 
    73         xml = self.serialize() 
    74         xml = ">\n".join(xml.split(">")) 
    75         xml = "\n<".join(xml.split("<")) 
    76         xml = '\n'.join(xml.split('\n\n')) 
    77         return xml 
     70        return prettyPrint(elem) 
     71#        xml = self.serialize() 
     72#        xml = ">\n".join(xml.split(">")) 
     73#        xml = "\n<".join(xml.split("<")) 
     74#        xml = '\n'.join(xml.split('\n\n')) 
     75#        return xml 
    7876     
    7977                          
    80 class AssertionETreeObject(ETreeObject, IssueInstantXMLObject): 
     78class AssertionElementTree(SAMLElementTree, IssueInstantXMLObject): 
    8179    """ElementTree based XML representation of Assertion class 
    8280    """ 
    8381    def __init__(self): 
    84         ETreeObject.__init__(self) 
     82        SAMLElementTree.__init__(self) 
    8583        IssueInstantXMLObject.__init__(self) 
    8684     
    8785    def create(self,  
    8886               assertion,  
    89                **attributeValueETreeObjectFactoryKw): 
     87               **attributeValueElementTreeFactoryKw): 
    9088        """Make a tree of a XML elements based on the assertion""" 
    9189        if not isinstance(assertion, Assertion): 
     
    10199            Assertion.VERSION_ATTRIB_NAME: str(assertion.version) 
    102100        } 
    103         self._elem = ElementTree.Element(str(Assertion.DEFAULT_ELEMENT_NAME),  
     101        self.__elem = ElementTree.Element(str(Assertion.DEFAULT_ELEMENT_NAME),  
    104102                                         **attrib) 
    105103         
     
    108106        ] = Assertion.DEFAULT_ELEMENT_NAME.prefix 
    109107         
    110         attributeStatementETreeObject = AttributeStatementETreeObject() 
     108        attributeStatementElementTree = AttributeStatementElementTree() 
    111109         
    112110        for attributeStatement in assertion.attributeStatements: 
    113             attributeStatementElem = attributeStatementETreeObject.create( 
     111            attributeStatementElem = attributeStatementElementTree.create( 
    114112                                        attributeStatement, 
    115                                         **attributeValueETreeObjectFactoryKw) 
    116             self._elem.append(attributeStatementElem) 
     113                                        **attributeValueElementTreeFactoryKw) 
     114            self.__elem.append(attributeStatementElem) 
    117115         
    118116        log.debug("Created Assertion:\n\n%s" %  
    119117                  ">\n".join(self.serialize().split(">"))) 
    120         return self._elem 
     118        return self.__elem 
    121119 
    122120   
    123 class AttributeStatementETreeObject(ETreeObject): 
     121class AttributeStatementElementTree(SAMLElementTree): 
    124122    """ElementTree XML representation of AttributeStatement""" 
    125123     
    126124    def create(self,  
    127125               attributeStatement,  
    128                **attributeValueETreeObjectFactoryKw): 
     126               **attributeValueElementTreeFactoryKw): 
    129127        if not isinstance(attributeStatement, AttributeStatement): 
    130128            raise TypeError("Expecting %r type got: %r" % (AttributeStatement,  
    131129                                                           attributeStatement)) 
    132130             
    133         self._elem = ElementTree.Element( 
     131        self.__elem = ElementTree.Element( 
    134132                                str(AttributeStatement.DEFAULT_ELEMENT_NAME)) 
    135133        ElementTree._namespace_map[ 
     
    137135        ] = AttributeStatement.DEFAULT_ELEMENT_NAME.prefix  
    138136 
    139         attributeETreeObject = AttributeETreeObject() 
     137        attributeElementTree = AttributeElementTree() 
    140138 
    141139        for attribute in attributeStatement.attributes: 
    142140            # Factory enables support for multiple attribute types 
    143             attributeElem = attributeETreeObject.create(attribute, 
    144                                         **attributeValueETreeObjectFactoryKw) 
    145             self._elem.append(attributeElem) 
    146          
    147         return self._elem 
    148      
    149  
    150 class AttributeETreeObject(ETreeObject): 
     141            attributeElem = attributeElementTree.create(attribute, 
     142                                        **attributeValueElementTreeFactoryKw) 
     143            self.__elem.append(attributeElem) 
     144         
     145        return self.__elem 
     146     
     147 
     148class AttributeElementTree(SAMLElementTree): 
    151149    """ElementTree XML representation of SAML Attribute object.  Extend 
    152150    to make Attribute types"""  
    153151 
    154     def create(self,  
     152    @classmethod 
     153    def create(cls,  
    155154               attribute,  
    156                **attributeValueETreeObjectFactoryKw): 
     155               **attributeValueElementTreeFactoryKw): 
    157156        """Make 'Attribute' element""" 
    158157         
     
    160159            raise TypeError("Expecting %r type got: %r"%(Attribute, attribute)) 
    161160             
    162         self._elem = ElementTree.Element(str(Attribute.DEFAULT_ELEMENT_NAME)) 
     161        elem = ElementTree.Element(str(Attribute.DEFAULT_ELEMENT_NAME)) 
    163162        ElementTree._namespace_map[ 
    164163            Attribute.DEFAULT_ELEMENT_NAME.namespaceURI 
     
    167166             
    168167        if attribute.friendlyName: 
    169             self._elem.set(Attribute.FRIENDLY_NAME_ATTRIB_NAME, 
    170                            attribute.friendlyName)   
     168            elem.set(Attribute.FRIENDLY_NAME_ATTRIB_NAME, 
     169                     attribute.friendlyName)  
     170              
    171171        if attribute.name: 
    172             self._elem.set(Attribute.NAME_ATTRIB_NAME, attribute.name) 
     172            elem.set(Attribute.NAME_ATTRIB_NAME, attribute.name) 
    173173         
    174174        if attribute.nameFormat: 
    175             self._elem.set(Attribute.NAME_FORMAT_ATTRIB_NAME, 
    176                            attribute.nameFormat) 
     175            elem.set(Attribute.NAME_FORMAT_ATTRIB_NAME, attribute.nameFormat) 
    177176 
    178177        for attributeValue in attribute.attributeValues: 
    179             factory = AttributeValueETreeObjectFactory( 
    180                                         **attributeValueETreeObjectFactoryKw) 
    181              
    182             attributeValueETreeObject = factory(attributeValue) 
    183              
    184             attributeValueElem=attributeValueETreeObject.create(attributeValue) 
    185             self._elem.append(attributeValueElem) 
    186              
    187         return self._elem 
     178            factory = AttributeValueElementTreeFactory( 
     179                                        **attributeValueElementTreeFactoryKw) 
     180             
     181            attributeValueElementTree = factory(attributeValue) 
     182             
     183            attributeValueElem=attributeValueElementTree.create(attributeValue) 
     184            elem.append(attributeValueElem) 
     185             
     186        return elem 
    188187  
    189      
    190 class AttributeValueETreeObjectBase(ETreeObject): 
     188    @classmethod 
     189    def parse(cls, elem): 
     190        """Parse ElementTree element into a SAML Attribute object 
     191         
     192        @type elem: ElementTree.Element 
     193        @param elem: Attribute as ElementTree XML element 
     194        @rtype: ndg.security.common.saml.Attribute 
     195        @return: SAML Attribute 
     196        """ 
     197        if not ElementTree.iselement(elem): 
     198            raise TypeError("Expecting %r input type for parsing; got %r" % 
     199                            (ElementTree.Element, elem)) 
     200 
     201        if getLocalName(elem) != Attribute.DEFAULT_ELEMENT_LOCAL_NAME: 
     202            raise XMLObjectParsingError("No \"%s\" element found" % 
     203                                        Attribute.DEFAULT_ELEMENT_LOCAL_NAME) 
     204             
     205        attribute = Attribute() 
     206             
     207        name = elem.attrib.get(Attribute.FORMAT_ATTRIB_NAME) 
     208        if name is not None: 
     209            attribute.name = name 
     210             
     211        friendlyName = elem.attrib.get(Attribute.FRIENDLY_NAME_ATTRIB_NAME) 
     212        if friendlyName is not None: 
     213            attribute.friendlyName = friendlyName 
     214             
     215        nameFormat = elem.attrib.get(Attribute.NAME_FORMAT_ATTRIB_NAME)     
     216        if nameFormat is not None: 
     217            attribute.nameFormat = nameFormat 
     218 
     219        for childElem in elem: 
     220            localName = getLocalName(childElem) 
     221            if localName != AttributeValue.DEFAULT_ELEMENT_LOCAL_NAME: 
     222                raise XMLObjectParsingError('Expecting "%s" element; found ' 
     223                                    '"%s"' % 
     224                                    (AttributeValue.DEFAULT_ELEMENT_LOCAL_NAME, 
     225                                     localName)) 
     226             
     227            attributeValue =  
     228            attribute.attributeValues.append(attributeValue) 
     229         
     230        return attribute 
     231         
     232     
     233class AttributeValueElementTreeBase(SAMLElementTree): 
    191234    """Base class ElementTree XML representation of SAML Attribute Value"""  
    192235     
    193     def create(self, attributeValue): 
     236    @classmethod 
     237    def create(cls, attributeValue): 
    194238        """Make 'Attribute' XML element""" 
    195239 
     
    198242                                                           attributeValue)) 
    199243             
    200         self._elem = ElementTree.Element( 
    201                                     str(AttributeValue.DEFAULT_ELEMENT_NAME)) 
     244        elem = ElementTree.Element(str(AttributeValue.DEFAULT_ELEMENT_NAME)) 
    202245        ElementTree._namespace_map[ 
    203246            AttributeValue.DEFAULT_ELEMENT_NAME.namespaceURI 
    204247        ] = AttributeValue.DEFAULT_ELEMENT_NAME.prefix 
    205248 
    206         return self._elem 
    207  
    208  
    209 class XSStringAttributeValueETreeObject(AttributeValueETreeObjectBase): 
     249        return elem 
     250 
     251 
     252class XSStringAttributeValueElementTree(AttributeValueElementTreeBase): 
    210253    """ElementTree XML representation of SAML String type Attribute Value"""  
    211254     
    212     def create(self, attributeValue): 
     255    @classmethod 
     256    def create(cls, attributeValue): 
    213257        """Create an XML representation of the input SAML Attribute Value""" 
    214         super(XSStringAttributeValueETreeObject, self).create(attributeValue) 
     258        elem = AttributeValueElementTreeBase.create(attributeValue) 
    215259         
    216260        if not isinstance(attributeValue, XSStringAttributeValue): 
     
    221265        # ElementTree._namespace_map because the prefixes are used for  
    222266        # attributes not element names         
    223         self._elem.set("%s:%s" % (SAMLConstants.XMLNS_PREFIX,  
    224                                   SAMLConstants.XSD_PREFIX), 
    225                        SAMLConstants.XSD_NS) 
     267        elem.set("%s:%s" % (SAMLConstants.XMLNS_PREFIX,  
     268                            SAMLConstants.XSD_PREFIX), 
     269                 SAMLConstants.XSD_NS) 
    226270                                    
    227         self._elem.set("%s:%s" % (SAMLConstants.XMLNS_PREFIX,  
    228                                   SAMLConstants.XSI_PREFIX), 
    229                        SAMLConstants.XSI_NS) 
    230          
    231         self._elem.set("%s:%s" % (SAMLConstants.XSI_PREFIX, 'type'),  
    232                        "%s:%s" % (SAMLConstants.XSD_PREFIX,  
    233                                   XSStringAttributeValue.TYPE_LOCAL_NAME)) 
    234  
    235         self._elem.text = attributeValue.value 
    236  
    237         return self._elem 
    238  
    239  
    240 class XSGroupRoleAttributeValueETreeObject(AttributeValueETreeObjectBase): 
     271        elem.set("%s:%s" % (SAMLConstants.XMLNS_PREFIX,  
     272                            SAMLConstants.XSI_PREFIX), 
     273                SAMLConstants.XSI_NS) 
     274         
     275        elem.set("%s:%s" % (SAMLConstants.XSI_PREFIX, 'type'),  
     276                 "%s:%s" % (SAMLConstants.XSD_PREFIX,  
     277                            XSStringAttributeValue.TYPE_LOCAL_NAME)) 
     278 
     279        elem.text = attributeValue.value 
     280 
     281        return elem 
     282 
     283 
     284class XSGroupRoleAttributeValueElementTree(AttributeValueElementTreeBase): 
    241285    """ElementTree XML representation of Earth System Grid custom Group/Role  
    242286    Attribute Value"""  
     
    244288    def create(self, attributeValue): 
    245289        """Create an XML representation of the input SAML Attribute Value""" 
    246         super(XSGroupRoleAttributeValueETreeObject,self).create(attributeValue) 
     290        super(XSGroupRoleAttributeValueElementTree,self).create(attributeValue) 
    247291         
    248292        if not isinstance(attributeValue, XSGroupRoleAttributeValue): 
     
    253297                                   ] = attributeValue.namespacePrefix 
    254298         
    255         self._elem.set(XSGroupRoleAttributeValue.GROUP_ATTRIB_NAME,  
     299        self.__elem.set(XSGroupRoleAttributeValue.GROUP_ATTRIB_NAME,  
    256300                       attributeValue.group) 
    257301         
    258         self._elem.set(XSGroupRoleAttributeValue.ROLE_ATTRIB_NAME,  
     302        self.__elem.set(XSGroupRoleAttributeValue.ROLE_ATTRIB_NAME,  
    259303                       attributeValue.role) 
    260304 
    261         return self._elem 
    262  
    263  
    264 class AttributeValueETreeObjectFactory(object): 
    265     """Factory for creating ElementTree representations of SAML Attribute  
    266     value types 
     305        return self.__elem 
     306 
     307 
     308class AttributeValueElementTreeFactory(object): 
     309    """Class factory for AttributeValue ElementTree classes.  These classes are 
     310    used to represent SAML Attribute value types 
     311     
     312    @type classMap: dict 
     313    @cvar classMap: mapping between SAML AttributeValue class and its  
     314    ElementTree handler class 
    267315    """ 
    268316    classMap = { 
    269         XSStringAttributeValue: XSStringAttributeValueETreeObject 
     317        XSStringAttributeValue: XSStringAttributeValueElementTree 
    270318    } 
    271319     
    272320    def __init__(self, customClassMap={}):  
    273321        """Set-up a SAML class to ElementTree mapping 
    274         """ 
    275         self.__classMap = AttributeValueETreeObjectFactory.classMap 
     322        @type customClassMap: dict 
     323        @param customClassMap: mapping for custom SAML AttributeValue classes 
     324        to their respective ElementTree based representations.  This appends 
     325        to AttributeValueElementTreeFactory.classMap 
     326        """ 
     327        self.__classMap = AttributeValueElementTreeFactory.classMap 
    276328        for samlClass, etreeClass in customClassMap.items():  
    277329            if not issubclass(samlClass, AttributeValue): 
     
    294346                            "SAML class %r" % samlObject.__class__) 
    295347             
    296         return xmlObjectClass() 
    297  
    298          
    299 class IssuerETreeObject(ETreeObject): 
     348        return return xmlObjectClass 
     349 
     350         
     351class IssuerElementTree(SAMLElementTree): 
    300352    """Represent a SAML Issuer element in XML using ElementTree""" 
    301353     
    302     def create(self, issuer): 
     354    @classmethod 
     355    def create(cls, issuer): 
    303356        """Create an XML representation of the input SAML issuer object""" 
    304357        if not isinstance(issuer, Issuer): 
     
    308361            Issuer.FORMAT_ATTRIB_NAME: issuer.format 
    309362        } 
    310         self._elem = ElementTree.Element(str(Issuer.DEFAULT_ELEMENT_NAME), 
    311                                          **attrib) 
     363        elem = ElementTree.Element(str(Issuer.DEFAULT_ELEMENT_NAME), **attrib) 
    312364        ElementTree._namespace_map[issuer.qname.namespaceURI 
    313365                                   ] = issuer.qname.prefix 
    314366                                    
    315         self._elem.text = issuer.value 
    316  
    317         return self._elem 
    318  
    319          
    320 class NameIdETreeObject(ETreeObject): 
     367        elem.text = issuer.value 
     368 
     369        return elem 
     370 
     371    @classmethod 
     372    def parse(cls, elem): 
     373        """Parse ElementTree element into a SAML Issuer instance""" 
     374        if not ElementTree.iselement(elem): 
     375            raise TypeError("Expecting %r input type for parsing; got %r" % 
     376                            (ElementTree.Element, elem)) 
     377 
     378        if getLocalName(elem) != Issuer.DEFAULT_ELEMENT_LOCAL_NAME: 
     379            raise XMLObjectParsingError("No \"%s\" element found" % 
     380                                        Issuer.DEFAULT_ELEMENT_LOCAL_NAME) 
     381             
     382        issuerFormat = elem.attrib.get(Issuer.FORMAT_ATTRIB_NAME) 
     383        if issuerFormat is None: 
     384            raise XMLObjectParsingError('No "%s" attribute found in "%s" ' 
     385                                        'element' % 
     386                                        (issuerFormat, 
     387                                         Issuer.DEFAULT_ELEMENT_LOCAL_NAME)) 
     388        issuer = Issuer() 
     389        issuer.format = issuerFormat 
     390        issuer.value = elem.text.strip()  
     391         
     392        return issuer 
     393         
     394class NameIdElementTree(SAMLElementTree): 
    321395    """Represent a SAML Name Identifier in XML using ElementTree""" 
    322396     
    323     def create(self, nameID): 
     397    @classmethod 
     398    def create(cls, nameID): 
    324399        """Create an XML representation of the input SAML Name Identifier 
    325         object""" 
     400        object 
     401        @type nameID: ndg.security.common.saml.Subject 
     402        @param nameID: SAML subject 
     403        @rtype: ElementTree.Element 
     404        @return: Name ID as ElementTree XML element""" 
     405         
    326406        if not isinstance(nameID, NameID): 
    327407            raise TypeError("Expecting %r class got %r" % (nameID,  
     
    330410            NameID.FORMAT_ATTRIB_NAME: nameID.format 
    331411        } 
    332         self._elem = ElementTree.Element(str(NameID.DEFAULT_ELEMENT_NAME), 
     412        elem = ElementTree.Element(str(NameID.DEFAULT_ELEMENT_NAME), 
    333413                                         **attrib) 
    334414         
     
    336416                                   ] = nameID.qname.prefix 
    337417         
    338         self._elem.text = nameID.value 
    339  
    340         return self._elem 
    341  
    342  
    343 class SubjectETreeObject(ETreeObject): 
     418        elem.text = nameID.value 
     419 
     420        return elem 
     421 
     422    @classmethod 
     423    def parse(cls, elem): 
     424        """Parse ElementTree element into a SAML NameID object 
     425         
     426        @type elem: ElementTree.Element 
     427        @param elem: Name ID as ElementTree XML element 
     428        @rtype: ndg.security.common.saml.NameID 
     429        @return: SAML Name ID 
     430        """ 
     431        if not ElementTree.iselement(elem): 
     432            raise TypeError("Expecting %r input type for parsing; got %r" % 
     433                            (ElementTree.Element, elem)) 
     434 
     435        if getLocalName(elem) != NameID.DEFAULT_ELEMENT_LOCAL_NAME: 
     436            raise XMLObjectParsingError("No \"%s\" element found" % 
     437                                        NameID.DEFAULT_ELEMENT_LOCAL_NAME) 
     438             
     439        format = elem.attrib.get(NameID.FORMAT_ATTRIB_NAME) 
     440        if format is None: 
     441            raise XMLObjectParsingError('No "%s" attribute found in "%s" ' 
     442                                        'element' % 
     443                                        (format, 
     444                                         NameID.DEFAULT_ELEMENT_LOCAL_NAME)) 
     445        nameID = NameID() 
     446        nameID.format = format 
     447        nameID.value = elem.text.strip()  
     448         
     449        return nameID 
     450 
     451 
     452class SubjectElementTree(SAMLElementTree): 
    344453    """Represent a SAML Subject in XML using ElementTree""" 
    345454     
    346     def create(self, subject): 
    347         """Create an XML representation of the input SAML subject object""" 
     455    @classmethod 
     456    def create(cls, subject): 
     457        """Create an XML representation of the input SAML subject object 
     458        @type subject: ndg.security.common.saml.Subject 
     459        @param subject: SAML subject 
     460        @rtype: ElementTree.Element 
     461        @return: subject as ElementTree XML element 
     462        """ 
    348463        if not isinstance(subject, Subject): 
    349464            raise TypeError("Expecting %r class got %r" % (subject,  
    350465                                                           type(Subject))) 
    351466             
    352         self._elem = ElementTree.Element(str(Subject.DEFAULT_ELEMENT_NAME)) 
     467        elem = ElementTree.Element(str(Subject.DEFAULT_ELEMENT_NAME)) 
    353468         
    354469        ElementTree._namespace_map[ 
     
    357472 
    358473             
    359         nameIdETreeObject = NameIdETreeObject() 
    360         nameIdElem = nameIdETreeObject.create(subject.nameID) 
    361         self._elem.append(nameIdElem) 
    362          
    363         return self._elem 
    364  
    365       
    366 class AttributeQueryETreeObject(ETreeObject, IssueInstantXMLObject): 
     474        nameIdElementTree = NameIdElementTree() 
     475        nameIdElem = nameIdElementTree.create(subject.nameID) 
     476        elem.append(nameIdElem) 
     477         
     478        return elem 
     479 
     480    @classmethod 
     481    def parse(cls, elem): 
     482        """Parse ElementTree element into a SAML Subject object 
     483         
     484        @type elem: ElementTree.Element 
     485        @param elem: subject as ElementTree XML element 
     486        @rtype: ndg.security.common.saml.Subject 
     487        @return: SAML subject 
     488        """ 
     489        if not ElementTree.iselement(elem): 
     490            raise TypeError("Expecting %r input type for parsing; got %r" % 
     491                            (ElementTree.Element, elem)) 
     492 
     493        if getLocalName(elem) != Subject.DEFAULT_ELEMENT_LOCAL_NAME: 
     494            raise XMLObjectParsingError("No \"%s\" element found" % 
     495                                        Subject.DEFAULT_ELEMENT_LOCAL_NAME) 
     496             
     497        if len(elem) != 1: 
     498            raise XMLObjectParseError("Expecting single Name ID child element " 
     499                                      "for SAML Subject element") 
     500             
     501        subject = Subject() 
     502        subject.nameID = NameIdElementTree.parse(elem[0]) 
     503         
     504        return subject 
     505     
     506     
     507class AttributeQueryElementTree(SAMLElementTree, IssueInstantXMLObject): 
    367508    """Represent a SAML Attribute Query in XML using ElementTree""" 
    368509    def __init__(self): 
    369         ETreeObject.__init__(self) 
     510        SAMLElementTree.__init__(self) 
    370511        IssueInstantXMLObject.__init__(self) 
    371512         
    372     def create(self,  
     513    @classmethod 
     514    def create(cls,  
    373515               attributeQuery,  
    374                **attributeValueETreeObjectFactoryKw): 
     516               **attributeValueElementTreeFactoryKw): 
    375517        """Create an XML representation of the input SAML Attribute Query 
    376518        object 
     519 
     520        @type attributeQuery: ndg.security.common.saml.AttributeQuery 
     521        @param attributeQuery: SAML Attribute Query 
     522        @rtype: ElementTree.Element 
     523        @return: Attribute Query as ElementTree XML element 
    377524        """ 
    378525        if not isinstance(attributeQuery, AttributeQuery): 
     
    381528             
    382529         
    383         issueInstant = AttributeQueryETreeObject.datetime2Str( 
     530        issueInstant = AttributeQueryElementTree.datetime2Str( 
    384531                                                attributeQuery.issueInstant) 
    385532        attrib = { 
     
    391538        } 
    392539                  
    393         self._elem = ElementTree.Element( 
    394                                     str(AttributeQuery.DEFAULT_ELEMENT_NAME), 
    395                                     **attrib) 
     540        elem = ElementTree.Element(str(AttributeQuery.DEFAULT_ELEMENT_NAME), 
     541                                   **attrib) 
    396542         
    397543        ElementTree._namespace_map[ 
     
    400546         
    401547             
    402         issuerETreeObject = IssuerETreeObject() 
    403         issuerElem = issuerETreeObject.create(attributeQuery.issuer) 
    404         self._elem.append(issuerElem) 
    405  
    406         subjectETreeObject = SubjectETreeObject() 
    407         subjectElem = subjectETreeObject.create(attributeQuery.subject) 
    408          
    409         self._elem.append(subjectElem) 
    410  
    411         attributeETreeObject = AttributeETreeObject() 
     548        issuerElementTree = IssuerElementTree() 
     549        issuerElem = issuerElementTree.create(attributeQuery.issuer) 
     550        elem.append(issuerElem) 
     551 
     552        subjectElementTree = SubjectElementTree() 
     553        subjectElem = subjectElementTree.create(attributeQuery.subject) 
     554         
     555        elem.append(subjectElem) 
     556 
     557        attributeElementTree = AttributeElementTree() 
    412558 
    413559        for attribute in attributeQuery.attributes: 
    414560            # Factory enables support for multiple attribute types 
    415             attributeElem = attributeETreeObject.create(attribute, 
    416                                         **attributeValueETreeObjectFactoryKw) 
    417             self._elem.append(attributeElem) 
    418          
    419         return self._elem 
     561            attributeElem = attributeElementTree.create(attribute, 
     562                                        **attributeValueElementTreeFactoryKw) 
     563            elem.append(attributeElem) 
     564         
     565        return elem 
     566 
     567    @classmethod 
     568    def parse(cls, elem): 
     569        """Parse ElementTree element into a SAML AttributeQuery object 
     570         
     571        @type elem: ElementTree.Element 
     572        @param elem: XML element containing the AttributeQuery 
     573        @rtype: ndg.security.common.saml.AttributeQuery 
     574        @return: AttributeQuery object 
     575        """ 
     576        if not ElementTree.iselement(elem): 
     577            raise TypeError("Expecting %r input type for parsing; got %r" % 
     578                            (ElementTree.Element, elem)) 
     579 
     580        if getLocalName(elem) != AttributeQuery.DEFAULT_ELEMENT_LOCAL_NAME: 
     581            raise XMLObjectParsingError("No \"%s\" element found" % 
     582                                    AttributeQuery.DEFAULT_ELEMENT_LOCAL_NAME) 
     583         
     584        # Unpack attributes from top-level element 
     585        attributeValues = [] 
     586        for attributeName in (AttributeQuery.VERSION_ATTRIB_NAME, 
     587                              AttributeQuery.ISSUE_INSTANT_ATTRIB_NAME, 
     588                              AttributeQuery.ID_ATTRIB_NAME): 
     589            attributeValue = elem.attrib.get(attributeName) 
     590            if attributeValue is None: 
     591                raise XMLObjectParsingError('No "%s" attribute found in "%s" ' 
     592                                 'element' % 
     593                                 (attributeName, 
     594                                  AttributeQuery.DEFAULT_ELEMENT_LOCAL_NAME)) 
     595                 
     596            attributeValues.append(attributeValue) 
     597         
     598        attributeQuery = AttributeQuery() 
     599        attributeQuery.version = SAMLVersion(attributeValues[0]) 
     600        if attributeQuery.version != SAMLVersion.VERSION_20: 
     601            raise NotImplementedError("Parsing for %r is implemented for " 
     602                                      "SAML version %s only; version %s is "  
     603                                      "not supported" %  
     604                                      (cls, 
     605                                       SAMLVersion(SAMLVersion.VERSION_20), 
     606                                       SAMLVersion(attributeQuery.version))) 
     607             
     608        attributeQuery.issueInstant = cls.str2Datetime(attributeValues[1]) 
     609        attributeQuery.id = attributeValues[2] 
     610         
     611        for childElem in elem: 
     612            localName = getLocalName(childElem) 
     613            if localName == Issuer.DEFAULT_ELEMENT_LOCAL_NAME: 
     614                # Parse Issuer 
     615                attributeQuery.issuer = IssuerElementTree.parse(childElem) 
     616                 
     617            elif localName == Subject.DEFAULT_ELEMENT_LOCAL_NAME: 
     618                # Parse Subject 
     619                attributeQuery.subject = SubjectElementTree.parse(childElem) 
     620            else: 
     621                raise XMLObjectParseError("Unrecognised AttributeQuery child " 
     622                                          "element \"%s\"" % localName) 
     623         
     624        return attributeQuery 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/utils/__init__.py

    r5550 r5554  
    120120         
    121121        # Put in namespace declaration if one doesn't already exist 
     122        # FIXME: namespace declaration handling is wrong for handling child 
     123        # element scope 
    122124        if namespace in declaredNss: 
    123125            nsDeclaration = '' 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/unit/saml/test_saml.py

    r5538 r5554  
    1919 
    2020from xml.etree.ElementTree import iselement 
     21from xml.etree import ElementTree 
    2122 
    2223from ndg.security.common.saml import Assertion, Attribute, AttributeValue, \ 
     
    240241                        "https://openid.localhost/philip.kershaw") 
    241242         
    242         attributeQueryETreeObject = AttributeQueryETreeObject() 
    243         attributeQueryETreeObject.create(attributeQuery) 
    244         xmlOutput = attributeQueryETreeObject.prettyPrint() 
     243        elem = AttributeQueryETreeObject.create(attributeQuery) 
     244        xmlOutput = AttributeQueryETreeObject.prettyPrint(elem) 
    245245        print(xmlOutput) 
    246246 
     
    254254                        "https://openid.localhost/philip.kershaw") 
    255255         
    256         attributeQueryETreeObject = AttributeQueryETreeObject() 
    257         attributeQueryETreeObject.create(attributeQuery) 
    258         xmlOutput = attributeQueryETreeObject.prettyPrint() 
    259          
    260         attributeQueryETreeObject2 = AttributeQueryETreeObject() 
     256        elem = AttributeQueryETreeObject.create(attributeQuery) 
     257#        xmlOutput = AttributeQueryETreeObject.prettyPrint(elem) 
     258        xmlOutput = AttributeQueryETreeObject.serialize(elem) 
    261259         
    262260        attributeQueryStream = StringIO() 
    263261        attributeQueryStream.write(xmlOutput) 
    264262        attributeQueryStream.seek(0) 
    265          
    266         attributeQuery2=attributeQueryETreeObject2.parse(attributeQueryStream) 
    267         xmlOutput2 = attributeQuery2.serialize() 
     263        print ElementTree.tostring(elem) 
     264        tree = ElementTree.parse(attributeQueryStream) 
     265        elem2 = tree.getroot() 
     266         
     267        attributeQuery2 = AttributeQueryETreeObject.parse(elem2) 
     268        xmlOutput2 = AttributeQueryETreeObject.serialize(elem2) 
    268269        self.assert_(xmlOutput == xmlOutput2) 
    269270         
Note: See TracChangeset for help on using the changeset viewer.