Changeset 5589


Ignore:
Timestamp:
10/08/09 16:05:32 (10 years ago)
Author:
pjkersha
Message:

ndg.security.test.unit.saml.test_saml: Working unit test for Attribute Query Response

Location:
TI12-security/trunk/python
Files:
1 added
8 edited

Legend:

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

    r5588 r5589  
    3333# Time module for use with validity times 
    3434from time import strftime, strptime 
    35 from datetime import datetime, timedelta 
     35from datetime import datetime 
    3636    
    37 from ndg.security.common.utils import QName, TypedList 
     37# TODO: remove ElementTree dependency - package should XML implementation 
     38# independent 
     39from ndg.security.common.utils.etree import QName 
     40from ndg.security.common.utils import TypedList 
    3841from ndg.security.common.saml.xml import SAMLConstants, XMLConstants 
    3942 
     
    4144class SAMLObject(object): 
    4245    """Base class for all SAML types""" 
    43  
    44  
    45 class SAMLVersion(object): 
     46    @classmethod 
     47    def parse(cls): 
     48        raise NotImplementedError() 
     49     
     50    @classmethod 
     51    def create(cls): 
     52        raise NotImplementedError() 
     53     
     54 
     55class SAMLVersion(SAMLObject): 
    4656    """Version helper class""" 
    4757    VERSION_10 = (1, 0) 
     
    8494        @return: SAML version tuple""" 
    8595        return tuple(version.split(".")) 
    86      
     96 
     97 
     98class Conditions(SAMLObject):  
     99    '''SAML 2.0 Core Conditions.''' 
     100     
     101    # Element local name. 
     102    DEFAULT_ELEMENT_LOCAL_NAME = "Conditions" 
     103 
     104    # Default element name. 
     105    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS,  
     106                                 DEFAULT_ELEMENT_LOCAL_NAME, 
     107                                 SAMLConstants.SAML20_PREFIX) 
     108 
     109    # Local name of the XSI type. 
     110    TYPE_LOCAL_NAME = "ConditionsType" 
     111 
     112    # QName of the XSI type. 
     113    TYPE_NAME = QName(SAMLConstants.SAML20_NS,  
     114                      TYPE_LOCAL_NAME, 
     115                      SAMLConstants.SAML20_PREFIX) 
     116 
     117    # NotBefore attribute name. 
     118    NOT_BEFORE_ATTRIB_NAME = "NotBefore" 
     119 
     120    # NotOnOrAfter attribute name. 
     121    NOT_ON_OR_AFTER_ATTRIB_NAME = "NotOnOrAfter" 
     122 
     123    def __init__(self): 
     124         
     125        # A Condition. 
     126        self.__conditions = [] 
     127     
     128        # Not Before conditions. 
     129        self.__notBefore = None 
     130     
     131        # Not On Or After conditions. 
     132        self.__notOnOrAfter = None 
     133 
     134    def _getNotBefore(self): 
     135        '''Get the date/time before which the assertion is invalid. 
     136         
     137        @return the date/time before which the assertion is invalid''' 
     138        return self.__notBefore 
     139     
     140    def _setNotBefore(self, value): 
     141        '''Sets the date/time before which the assertion is invalid. 
     142         
     143        @param newNotBefore the date/time before which the assertion is invalid 
     144        ''' 
     145        if not isinstance(value, datetime): 
     146            raise TypeError('Expecting "datetime" type for "notBefore", ' 
     147                            'got %r' % type(value)) 
     148        self.__notBefore = value 
     149 
     150    def _getNotOnOrAfter(self): 
     151        '''Gets the date/time on, or after, which the assertion is invalid. 
     152         
     153        @return the date/time on, or after, which the assertion is invalid' 
     154        ''' 
     155        return self.__notBefore 
     156     
     157    def _setNotOnOrAfter(self, value): 
     158        '''Sets the date/time on, or after, which the assertion is invalid. 
     159         
     160        @param newNotOnOrAfter the date/time on, or after, which the assertion  
     161        is invalid 
     162        ''' 
     163        if not isinstance(notOnOrAfter, datetime): 
     164            raise TypeError('Expecting "datetime" type for "notOnOrAfter", ' 
     165                            'got %r' % type(value)) 
     166        self.__notOnOrAfter = notOnOrAfter   
     167 
     168    def _getConditions(self): 
     169        '''Gets all the conditions on the assertion. 
     170         
     171        @return all the conditions on the assertion 
     172        ''' 
     173        return self.__conditions 
     174     
     175    conditions = property(fget=_getConditions, 
     176                          doc="List of conditions") 
     177     
     178    def _getAudienceRestrictions(self): 
     179        '''Gets the audience restriction conditions for the assertion. 
     180         
     181        @return the audience restriction conditions for the assertion 
     182        ''' 
     183        raise NotImplementedError() 
     184 
     185    def _getOneTimeUse(self): 
     186        '''Gets the OneTimeUse condition for the assertion. 
     187         
     188        @return the OneTimeUse condition for the assertion 
     189        ''' 
     190        raise NotImplementedError() 
     191 
     192    def _getProxyRestriction(self):     
     193        '''Gets the ProxyRestriction condition for the assertion. 
     194         
     195        @return the ProxyRestriction condition for the assertion 
     196        ''' 
     197        raise NotImplementedError() 
     198 
    87199 
    88200class Assertion(SAMLObject): 
     
    119231    ID_ATTRIB_NAME = "ID" 
    120232 
    121     def __init__(self, **xmlSecDocKw): 
    122         """@type **xmlSecDocKw: dict 
    123         @param **xmlSecDocKw: see XMLSec.XMLSec class for an explanation. 
    124         Keywords include, filePath for the cert. for reading/writing and 
    125         cert./private key settings for digital signature and verification.""" 
    126  
     233    def __init__(self): 
    127234        # Base class initialisation 
    128235        super(Assertion, self).__init__() 
     
    133240        self.__issuer = None 
    134241        self.__subject = None 
    135         self.__conditions = [] 
     242         
     243        self.__conditions = None 
    136244        self.__advice = None 
    137         self.__statements = [] 
     245        self.__statements = TypedList(Statement) 
     246         
     247        # TODO: Implement AuthnStatement and AuthzDecisionStatement classes 
    138248        self.__authnStatements = [] 
    139249        self.__authzDecisionStatements = [] 
    140         self.__attributeStatements = [] 
     250        self.__attributeStatements = TypedList(AttributeStatement) 
    141251         
    142252    def _get_version(self): 
     
    200310    def _set_issuer(self, issuer): 
    201311        """Set issuer""" 
    202         if not isinstance(issuer, basestring): 
    203             raise TypeError("issuer must be a string, got %r" %  
    204                             issuer.__class__) 
    205          
     312        if not isinstance(issuer, Issuer): 
     313            raise TypeError("issuer must be %r, got %r" % (Issuer,  
     314                                                           type(issuer))) 
    206315        self.__issuer = issuer 
    207316     
     
    216325    def _set_subject(self, subject): 
    217326        """Set subject string.""" 
    218         if not isinstance(subject, basestring): 
    219             raise TypeError("subject must be a string, got %r" %  
    220                             subject.__class__) 
     327        if not isinstance(subject, Subject): 
     328            raise TypeError("subject must be %r, got %r" % (Subject,  
     329                                                            type(subject))) 
    221330 
    222331        self.__subject = subject 
     
    230339                       doc="Attribute Assertion subject") 
    231340     
    232     def _set_conditions(self, conditions): 
    233         """Set assertion conditions.""" 
    234         if not isinstance(conditions, (list, tuple)): 
    235             raise TypeError("conditions must be a string") 
    236  
    237         self.__conditions = list(conditions) 
    238      
    239341    def _get_conditions(self): 
    240342        """Get conditions string.""" 
    241343        return self.__conditions 
     344     
     345    def _set_conditions(self, value): 
     346        """Get conditions string.""" 
     347        if not isinstance(value, Conditions): 
     348            raise TypeError("Conditions must be %r, got %r" % (Conditions,  
     349                                                            type(conditions))) 
     350 
     351        self.__conditions = value 
    242352 
    243353    conditions = property(fget=_get_conditions, 
    244                           fset=_set_conditions,  
     354                          fset=_set_conditions, 
    245355                          doc="Attribute Assertion conditions") 
    246356     
     
    260370                      doc="Attribute Assertion advice") 
    261371     
    262     def _set_statements(self, statements): 
    263         """Set statements list.""" 
    264         if not isinstance(statements, (list, tuple)): 
    265             raise TypeError("statements must be a list/tuple.") 
    266  
    267         self.__statements = list(statements) 
    268      
    269372    def _get_statements(self): 
    270373        """Get statements string.""" 
     
    272375 
    273376    statements = property(fget=_get_statements, 
    274                           fset=_set_statements,  
    275377                          doc="Attribute Assertion statements") 
    276  
    277     def _set_authnStatements(self, authnStatements): 
    278         """Set authentication statements string.""" 
    279         if not isinstance(authnStatements, (list, tuple)): 
    280             raise TypeError("authnStatements must be a list/tuple") 
    281  
    282         self.__authnStatements = list(authnStatements) 
    283378     
    284379    def _get_authnStatements(self): 
     
    287382 
    288383    authnStatements = property(fget=_get_authnStatements, 
    289                                fset=_set_authnStatements,  
    290384                               doc="Attribute Assertion authentication " 
    291385                                   "statements") 
    292      
    293     def _set_authzDecisionStatements(self, authzDecisionStatements): 
    294         """Set authorisation decision statements.""" 
    295         if not isinstance(authzDecisionStatements, (list, tuple)): 
    296             raise TypeError("authorisation decision statements must be a " 
    297                             "list/tuple") 
    298  
    299         self.__authzDecisionStatements = list(authzDecisionStatements) 
    300386     
    301387    def _get_authzDecisionStatements(self): 
     
    304390 
    305391    authzDecisionStatements = property(fget=_get_authzDecisionStatements, 
    306                                        fset=_set_authzDecisionStatements,  
    307392                                       doc="Attribute Assertion authorisation " 
    308393                                           "decision statements") 
    309      
    310  
    311     def _set_attributeStatements(self, attributeStatements): 
    312         """Set attribute statements for the asssertion.""" 
    313         if not isinstance(attributeStatements, (list, tuple)): 
    314             raise TypeError("attributeStatements must be a list/tuple") 
    315  
    316         self.__attributeStatements = list(attributeStatements) 
    317394     
    318395    def _get_attributeStatements(self): 
     
    321398 
    322399    attributeStatements = property(fget=_get_attributeStatements, 
    323                                fset=_set_attributeStatements,  
    324                                doc="Attribute Assertion attribute statements") 
     400                                   doc="Attribute Assertion attribute " 
     401                                       "statements") 
    325402 
    326403 
     
    10611138        """Set issuer of request""" 
    10621139        if not isinstance(issuer, Issuer): 
    1063             raise TypeError("\"issuer\" must be a %r, got %r" %  
    1064                             issuer.__class__) 
     1140            raise TypeError('"issuer" must be a %r, got %r' % (Issuer,  
     1141                                                               type(issuer))) 
    10651142         
    10661143        self.__issuer = issuer 
     
    10931170 
    10941171 
    1095 class StatusResponseType(SAMLObject): 
    1096     '''SAML 2.0 Core Status Response Type 
    1097     ''' 
     1172class StatusDetail(SAMLObject): 
     1173    '''Implementation of SAML 2.0 StatusDetail.''' 
     1174     
     1175    # Local Name of StatusDetail. 
     1176    DEFAULT_ELEMENT_LOCAL_NAME = "StatusDetail" 
     1177 
     1178    # Default element name. 
     1179    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS,  
     1180                                 DEFAULT_ELEMENT_LOCAL_NAME, 
     1181                                 SAMLConstants.SAML20P_PREFIX) 
    10981182 
    10991183    # Local name of the XSI type. 
    1100     TYPE_LOCAL_NAME = "StatusResponseType" 
     1184    TYPE_LOCAL_NAME = "StatusDetailType" 
    11011185 
    11021186    # QName of the XSI type. 
     
    11041188                      TYPE_LOCAL_NAME, 
    11051189                      SAMLConstants.SAML20P_PREFIX) 
     1190     
     1191    def __init__(self): 
     1192        # child "any" elements. 
     1193        self.__unknownChildren = TypedList(SAMLObject)          
     1194        self.__qname = QName( 
     1195                namespaceURI=StatusDetail.DEFAULT_ELEMENT_NAME.namespaceURI, 
     1196                tag=StatusDetail.DEFAULT_ELEMENT_NAME, 
     1197                prefix=StatusDetail.DEFAULT_ELEMENT_NAME.prefix) 
     1198     
     1199    def getUnknownXMLObjects(self, qname=None):  
     1200        if qname is not None: 
     1201            if not isinstance(qname, QName): 
     1202                raise TypeError("\"qname\" must be a %r derived type, " 
     1203                                "got %r" % (QName, type(qname))) 
     1204                 
     1205            children = [] 
     1206            for child in self.__unknownChildren: 
     1207                childQName = getattr(child, "qname", None) 
     1208                if childQName is not None: 
     1209                    if childQName.namespaceURI == qname.namespaceURI or \ 
     1210                       childQName.localPart == qname.localPart: 
     1211                        children.append(child) 
     1212                         
     1213            return children 
     1214        else: 
     1215            return self.__unknownChildren 
     1216     
     1217    unknownChildren = property(fget=getUnknownXMLObjects, 
     1218                               doc="Child objects of Status Detail - may be " 
     1219                                   "any type") 
     1220                 
     1221    def _getQName(self): 
     1222        return self.__qname 
     1223         
     1224    def _setQName(self, value): 
     1225        if not isinstance(value, QName): 
     1226            raise TypeError("\"qname\" must be a %r derived type, " 
     1227                            "got %r" % (QName, type(value))) 
     1228             
     1229        self.__qname = value 
     1230 
     1231    qname = property(fget=_getQName, fset=_setQName, doc="qualified name") 
     1232     
     1233 
     1234class StatusMessage(SAMLObject): 
     1235    '''Implementation of SAML 2.0 Status Message.''' 
     1236 
     1237    def __init__(self): 
     1238        # Value attribute URI. 
     1239        self.__value = None         
     1240        self.__qname = None 
     1241               
     1242    def _getValue(self): 
     1243        return self.__value 
     1244         
     1245    def _setValue(self, value): 
     1246        if not isinstance(value, basestring): 
     1247            raise TypeError("\"value\" must be a basestring derived type, " 
     1248                            "got %r" % value.__class__) 
     1249             
     1250        self.__value = value 
     1251 
     1252    value = property(fget=_getValue, fset=_setValue,  
     1253                     doc="Status message value") 
     1254                 
     1255    def _getQName(self): 
     1256        return self.__qname 
     1257         
     1258    def _setQName(self, value): 
     1259        if not isinstance(value, QName): 
     1260            raise TypeError("\"qname\" must be a %r derived type, " 
     1261                            "got %r" % (QName, type(value))) 
     1262             
     1263        self.__qname = value 
     1264 
     1265    qname = property(fget=_getQName, fset=_setQName, doc="qualified name") 
     1266 
     1267 
     1268class StatusCode(SAMLObject): 
     1269    '''Implementation of SAML 2.0 StatusCode.''' 
     1270    # Local Name of StatusCode. 
     1271    DEFAULT_ELEMENT_LOCAL_NAME = "StatusCode" 
     1272 
     1273    # Default element name. 
     1274    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS,  
     1275                                 DEFAULT_ELEMENT_LOCAL_NAME, 
     1276                                 SAMLConstants.SAML20P_PREFIX) 
     1277 
     1278    # Local name of the XSI type. 
     1279    TYPE_LOCAL_NAME = "StatusCodeType" 
     1280 
     1281    # QName of the XSI type. 
     1282    TYPE_NAME = QName(SAMLConstants.SAML20P_NS,  
     1283                      TYPE_LOCAL_NAME, 
     1284                      SAMLConstants.SAML20P_PREFIX) 
     1285 
     1286    # Local Name of the Value attribute. 
     1287    VALUE_ATTRIB_NAME = "Value" 
     1288 
     1289    # URI for Success status code. 
     1290    SUCCESS_URI = "urn:oasis:names:tc:SAML:2.0:status:Success" 
     1291 
     1292    # URI for Requester status code. 
     1293    REQUESTER_URI = "urn:oasis:names:tc:SAML:2.0:status:Requester" 
     1294 
     1295    # URI for Responder status code. 
     1296    RESPONDER_URI = "urn:oasis:names:tc:SAML:2.0:status:Responder" 
     1297 
     1298    # URI for VersionMismatch status code. 
     1299    VERSION_MISMATCH_URI = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch" 
     1300 
     1301    # URI for AuthnFailed status code. 
     1302    AUTHN_FAILED_URI = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed" 
     1303 
     1304    # URI for InvalidAttrNameOrValue status code. 
     1305    INVALID_ATTR_NAME_VALUE_URI = \ 
     1306                "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue" 
     1307 
     1308    # URI for InvalidNameIDPolicy status code. 
     1309    INVALID_NAMEID_POLICY_URI = \ 
     1310                "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy" 
     1311 
     1312    # URI for NoAuthnContext status code. 
     1313    NO_AUTHN_CONTEXT_URI = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext" 
     1314 
     1315    # URI for NoAvailableIDP status code. 
     1316    NO_AVAILABLE_IDP_URI = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP" 
     1317 
     1318    # URI for NoPassive status code. 
     1319    NO_PASSIVE_URI = "urn:oasis:names:tc:SAML:2.0:status:NoPassive" 
     1320 
     1321    # URI for NoSupportedIDP status code. 
     1322    NO_SUPPORTED_IDP_URI = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP" 
     1323 
     1324    # URI for PartialLogout status code. 
     1325    PARTIAL_LOGOUT_URI = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout" 
     1326 
     1327    # URI for ProxyCountExceeded status code. 
     1328    PROXY_COUNT_EXCEEDED_URI = \ 
     1329                "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded" 
     1330 
     1331    # URI for RequestDenied status code. 
     1332    REQUEST_DENIED_URI = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied" 
     1333 
     1334    # URI for RequestUnsupported status code. 
     1335    REQUEST_UNSUPPORTED_URI = \ 
     1336                "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported" 
     1337 
     1338    # URI for RequestVersionDeprecated status code. 
     1339    REQUEST_VERSION_DEPRECATED_URI = \ 
     1340                "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated" 
     1341 
     1342    # URI for RequestVersionTooHigh status code. 
     1343    REQUEST_VERSION_TOO_HIGH_URI = \ 
     1344                "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh" 
     1345     
     1346    # URI for RequestVersionTooLow status code. 
     1347    REQUEST_VERSION_TOO_LOW_URI = \ 
     1348                "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow" 
     1349 
     1350    # URI for ResourceNotRecognized status code. 
     1351    RESOURCE_NOT_RECOGNIZED_URI = \ 
     1352                "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized" 
     1353 
     1354    # URI for TooManyResponses status code. 
     1355    TOO_MANY_RESPONSES = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses" 
     1356 
     1357    # URI for UnknownAttrProfile status code. 
     1358    UNKNOWN_ATTR_PROFILE_URI = \ 
     1359                "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile" 
     1360 
     1361    # URI for UnknownPrincipal status code. 
     1362    UNKNOWN_PRINCIPAL_URI = \ 
     1363                "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal" 
     1364 
     1365    # URI for UnsupportedBinding status code. 
     1366    UNSUPPORTED_BINDING_URI = \ 
     1367                "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding" 
     1368 
     1369    def __init__(self): 
     1370        # Value attribute URI. 
     1371        self.__value = None 
     1372     
     1373        # Nested secondary StatusCode child element. 
     1374        self.__childStatusCode = None 
     1375         
     1376        self.__qname = QName( 
     1377                    namespaceURI=StatusCode.DEFAULT_ELEMENT_NAME.namespaceURI, 
     1378                    tag=StatusCode.DEFAULT_ELEMENT_NAME, 
     1379                    prefix=StatusCode.DEFAULT_ELEMENT_NAME.prefix) 
     1380 
     1381    def _getStatusCode(self):  
     1382        return self.__childStatusCode 
     1383     
     1384    def _setStatusCode(self, value): 
     1385        if not isinstance(value, StatusCode): 
     1386            raise TypeError('Child "statusCode" must be a %r derived type, ' 
     1387                            "got %r" % (StatusCode, type(value))) 
     1388             
     1389        self.__childStatusCode = value 
     1390 
     1391    value = property(fget=_getStatusCode,  
     1392                     fset=_setStatusCode,  
     1393                     doc="Child Status code") 
     1394               
     1395    def _getValue(self): 
     1396        return self.__value 
     1397         
     1398    def _setValue(self, value): 
     1399        if not isinstance(value, basestring): 
     1400            raise TypeError("\"value\" must be a basestring derived type, " 
     1401                            "got %r" % value.__class__) 
     1402             
     1403        self.__value = value 
     1404 
     1405    value = property(fget=_getValue, fset=_setValue, doc="Status code value") 
     1406                 
     1407    def _getQName(self): 
     1408        return self.__qname 
     1409         
     1410    def _setQName(self, value): 
     1411        if not isinstance(value, QName): 
     1412            raise TypeError("\"qname\" must be a %r derived type, " 
     1413                            "got %r" % (QName, type(value))) 
     1414             
     1415        self.__qname = value 
     1416 
     1417    qname = property(fget=_getQName, fset=_setQName, doc="qualified name") 
     1418         
     1419 
     1420class Status(SAMLObject):  
     1421    ''' 
     1422    SAML 2.0 Core Status. 
     1423    ''' 
     1424     
     1425    # Local Name of Status. 
     1426    DEFAULT_ELEMENT_LOCAL_NAME = "Status" 
     1427 
     1428    # Default element name. 
     1429    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS,  
     1430                                 DEFAULT_ELEMENT_LOCAL_NAME, 
     1431                                 SAMLConstants.SAML20P_PREFIX) 
     1432 
     1433    # Local name of the XSI type. 
     1434    TYPE_LOCAL_NAME = "StatusType" 
     1435 
     1436    # QName of the XSI type. 
     1437    TYPE_NAME = QName(SAMLConstants.SAML20P_NS,  
     1438                      TYPE_LOCAL_NAME, 
     1439                      SAMLConstants.SAML20P_PREFIX) 
     1440 
     1441    def __init__(self): 
     1442        # StatusCode element. 
     1443        self.__statusCode = None 
     1444     
     1445        # StatusMessage element. 
     1446        self.__statusMessage = None 
     1447     
     1448        # StatusDetail element.  
     1449        self.__statusDetail = None 
     1450         
     1451        self.__qname = QName( 
     1452                        namespaceURI=Status.DEFAULT_ELEMENT_NAME.namespaceURI, 
     1453                        tag=Status.DEFAULT_ELEMENT_NAME, 
     1454                        prefix=Status.DEFAULT_ELEMENT_NAME.prefix) 
     1455                 
     1456    def _getQName(self): 
     1457        return self.__qname 
     1458         
     1459    def _setQName(self, value): 
     1460        if not isinstance(value, QName): 
     1461            raise TypeError("\"qname\" must be a %r derived type, " 
     1462                            "got %r" % (QName, type(value))) 
     1463             
     1464        self.__qname = value 
     1465 
     1466    qname = property(fget=_getQName, fset=_setQName, doc="qualified name") 
     1467         
     1468    def _getStatusCode(self): 
     1469        ''' 
     1470        Gets the Code of this Status. 
     1471         
     1472        @return Status StatusCode 
     1473        ''' 
     1474        return self.__statusCode 
     1475 
     1476    def _setStatusCode(self, value): 
     1477        ''' 
     1478        Sets the Code of this Status. 
     1479         
     1480        @param newStatusCode the Code of this Status 
     1481        ''' 
     1482        if not isinstance(value, StatusCode): 
     1483            raise TypeError('"statusCode" must be a %r derived type, ' 
     1484                            "got %r" % (StatusCode, type(value))) 
     1485             
     1486        self.__statusCode = value 
     1487         
     1488    statusCode = property(fget=_getStatusCode, 
     1489                          fset=_setStatusCode, 
     1490                          doc="status code object") 
     1491     
     1492    def _getStatusMessage(self): 
     1493        ''' 
     1494        Gets the Message of this Status. 
     1495         
     1496        @return Status StatusMessage 
     1497        ''' 
     1498        return self.__statusMessage 
     1499 
     1500    def _setStatusMessage(self, value): 
     1501        ''' 
     1502        Sets the Message of this Status. 
     1503         
     1504        @param newStatusMessage the Message of this Status 
     1505        ''' 
     1506        if not isinstance(value, basestring): 
     1507            raise TypeError('"statusMessage" must be a %r derived type, ' 
     1508                            "got %r" % (basestring, type(value))) 
     1509             
     1510        self.__statusMessage = value 
     1511         
     1512    statusMessage = property(fget=_getStatusMessage, 
     1513                             fset=_setStatusMessage, 
     1514                             doc="status message") 
     1515 
     1516    def _getStatusDetail(self): 
     1517        ''' 
     1518        Gets the Detail of this Status. 
     1519         
     1520        @return Status StatusDetail 
     1521        ''' 
     1522        return self.__statusDetail 
     1523     
     1524    def _setStatusDetail(self, value): 
     1525        ''' 
     1526        Sets the Detail of this Status. 
     1527         
     1528        @param newStatusDetail the Detail of this Status 
     1529        ''' 
     1530        self.__statusDetail = value 
     1531         
     1532    statusDetail = property(fget=_getStatusDetail, 
     1533                            fset=_setStatusDetail, 
     1534                            doc="status message") 
     1535 
     1536 
     1537class StatusResponseType(SAMLObject): 
     1538    '''SAML 2.0 Core Status Response Type 
     1539    ''' 
     1540 
     1541    # Local name of the XSI type. 
     1542    TYPE_LOCAL_NAME = "StatusResponseType" 
     1543 
     1544    # QName of the XSI type. 
     1545    TYPE_NAME = QName(SAMLConstants.SAML20P_NS,  
     1546                      TYPE_LOCAL_NAME, 
     1547                      SAMLConstants.SAML20P_PREFIX) 
    11061548 
    11071549    # ID attribute name 
     
    11461588    def __init__(self): 
    11471589        self.__qname = None 
     1590         
    11481591        self.__version = SAMLVersion(SAMLVersion.VERSION_20) 
    11491592        self.__id = None 
     
    12191662        request 
    12201663        ''' 
     1664        if not isinstance(value, basestring): 
     1665            raise TypeError('Expecting basestring derived type for ' 
     1666                            '"inResponseTo", got %r' % type(value)) 
    12211667        self.__inResponseTo = value 
    12221668         
     
    12911737                       fset=_set_consent, 
    12921738                       doc="Consent for response") 
    1293      
     1739    
    12941740    def _set_issuer(self, issuer): 
    1295         """Set issuer""" 
    1296         if not isinstance(issuer, basestring): 
    1297             raise TypeError("issuer must be a string, got %r" %  
    1298                             issuer.__class__) 
    1299          
     1741        """Set issuer of response""" 
     1742        if not isinstance(issuer, Issuer): 
     1743            raise TypeError('"issuer" must be a %r, got %r' % (Issuer, 
     1744                                                               type(issuer))) 
    13001745        self.__issuer = issuer 
    13011746     
     
    13081753                      doc="Issuer of response") 
    13091754     
    1310     def _getStatus(self, value): 
     1755    def _getStatus(self): 
    13111756        '''Gets the Status of this response. 
    13121757         
     
    13201765        @param newStatus the Status of this response 
    13211766        ''' 
     1767        if not isinstance(value, Status): 
     1768            raise TypeError('"status" must be a %r, got %r' % (Status, 
     1769                                                               type(value))) 
    13221770        self.__status = value 
     1771         
     1772    status = property(fget=_getStatus, fset=_setStatus, doc="Response status")     
    13231773         
    13241774    def _get_extensions(self): 
     
    13341784        @param value: the Extensions of this response 
    13351785        ''' 
     1786        if not isinstance(value, (list, tuple)): 
     1787            raise TypeError('Expecting list or tuple for "extensions", got %r' 
     1788                            % type(value)) 
    13361789        self.__extensions = value 
    13371790         
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/saml/xml/etree.py

    r5588 r5589  
    3737    import cElementTree, ElementTree 
    3838 
    39 from ndg.security.common.saml import SAMLObject, Assertion, Attribute, \ 
    40     AttributeStatement, AttributeValue, XSStringAttributeValue, \ 
    41     XSGroupRoleAttributeValue, AttributeQuery, Subject, NameID, Issuer, \ 
    42     SAMLVersion 
     39from ndg.security.common.saml import SAMLObject, Conditions, Assertion, \ 
     40    Attribute, AttributeStatement, AttributeValue, XSStringAttributeValue, \ 
     41    XSGroupRoleAttributeValue, Response, AttributeQuery, Subject, NameID, \ 
     42    Issuer, SAMLVersion, Response, Status, StatusCode 
    4343     
    4444from ndg.security.common.saml.xml import XMLObject, IssueInstantXMLObject, \ 
    4545    XMLObjectParseError, SAMLConstants 
    4646 
    47 from ndg.security.common.utils import QName, getLocalName, prettyPrint 
     47from ndg.security.common.utils.etree import QName, getLocalName, prettyPrint 
    4848 
    4949class SAMLElementTree(XMLObject): 
     
    6969        """Basic pretty printing separating each element on to a new line""" 
    7070        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 
    76      
    77                           
    78 class AssertionElementTree(SAMLElementTree, IssueInstantXMLObject): 
     71 
     72 
     73class ConditionsElementTree(Conditions, IssueInstantXMLObject): 
     74    """ElementTree based XML representation of Conditions class 
     75    """ 
     76     
     77    @classmethod 
     78    def create(cls, conditions): 
     79        """Make a tree of a XML elements based on the assertion conditions""" 
     80         
     81        if not isinstance(conditions, Conditions): 
     82            raise TypeError("Expecting %r type got: %r"%(Conditions,condition)) 
     83         
     84        notBeforeStr = cls.datetime2Str(conditions.notBefore) 
     85        notOnOrAfterStr = cls.datetime2Str(conditions.notOnOrAfter) 
     86        attrib = { 
     87            cls.NOT_BEFORE_ATTRIB_NAME: notBeforeStr, 
     88            cls.NOT_ON_OR_AFTER_ATTRIB_NAME: notOnOrAfterStr, 
     89        } 
     90        elem = ElementTree.Element(str(cls.DEFAULT_ELEMENT_NAME), **attrib) 
     91         
     92        ElementTree._namespace_map[cls.DEFAULT_ELEMENT_NAME.namespaceURI 
     93                                   ] = cls.DEFAULT_ELEMENT_NAME.prefix 
     94 
     95        for condition in conditions.conditions: 
     96            raise NotImplementedError("Conditions list creation is not " 
     97                                      "implemented") 
     98                 
     99        return elem 
     100                
     101class AssertionElementTree(Assertion, IssueInstantXMLObject): 
    79102    """ElementTree based XML representation of Assertion class 
    80103    """ 
    81     def __init__(self): 
    82         SAMLElementTree.__init__(self) 
    83         IssueInstantXMLObject.__init__(self) 
    84104     
    85105    @classmethod 
     
    88108               **attributeValueElementTreeFactoryKw): 
    89109        """Make a tree of a XML elements based on the assertion""" 
     110         
    90111        if not isinstance(assertion, Assertion): 
    91112            raise TypeError("Expecting %r type got: %r"%(Assertion, assertion)) 
    92113         
    93         issueInstant = IssueInstantXMLObject.datetime2Str( 
    94                                                         assertion.issueInstant) 
     114        issueInstant = cls.datetime2Str(assertion.issueInstant) 
    95115        attrib = { 
    96             Assertion.ID_ATTRIB_NAME: assertion.id, 
    97             Assertion.ISSUE_INSTANT_ATTRIB_NAME: issueInstant, 
     116            cls.ID_ATTRIB_NAME: assertion.id, 
     117            cls.ISSUE_INSTANT_ATTRIB_NAME: issueInstant, 
    98118             
    99119            # Nb. Version is a SAMLVersion instance and requires explicit cast 
    100             Assertion.VERSION_ATTRIB_NAME: str(assertion.version) 
     120            cls.VERSION_ATTRIB_NAME: str(assertion.version) 
    101121        } 
    102         elem = ElementTree.Element(str(Assertion.DEFAULT_ELEMENT_NAME), 
    103                                    **attrib) 
    104          
    105         ElementTree._namespace_map[  
    106             Assertion.DEFAULT_ELEMENT_NAME.namespaceURI 
    107         ] = Assertion.DEFAULT_ELEMENT_NAME.prefix 
    108          
     122        elem = ElementTree.Element(str(cls.DEFAULT_ELEMENT_NAME), **attrib) 
     123         
     124        ElementTree._namespace_map[cls.DEFAULT_ELEMENT_NAME.namespaceURI 
     125                                   ] = cls.DEFAULT_ELEMENT_NAME.prefix 
     126         
     127        if assertion.issuer is not None: 
     128            issuerElem = IssuerElementTree.create(assertion.issuer) 
     129            elem.append(issuerElem) 
     130         
     131        if assertion.subject is not None: 
     132            subjectElem = SubjectElementTree.create(assertion.subject) 
     133            elem.append(subjectElem) 
     134 
     135        if assertion.advice: 
     136            raise NotImplementedError("Assertion Advice creation is not " 
     137                                      "implemented") 
     138 
     139        if assertion.conditions is not None: 
     140            conditionsElem = ConditionsElementTree.create(assertion.conditions) 
     141            elem.append(conditionsElem) 
     142             
     143        for statement in assertion.statements: 
     144            raise NotImplementedError("Assertion Statement creation is not " 
     145                                      "implemented") 
     146         
     147        for authnStatement in assertion.authnStatements: 
     148            raise NotImplementedError("Assertion Authentication Statement " 
     149                                      "creation is not implemented") 
     150         
     151        for authzDecisionStatement in assertion.authzDecisionStatements: 
     152            raise NotImplementedError("Assertion Authorisation Decision " 
     153                                      "Statement creation is not implemented") 
     154             
    109155        for attributeStatement in assertion.attributeStatements: 
    110156            attributeStatementElem = AttributeStatementElementTree.create( 
     
    263309 
    264310 
    265 class XSStringAttributeValueElementTree(AttributeValueElementTreeBase): 
     311class XSStringAttributeValueElementTree(AttributeValueElementTreeBase, 
     312                                        XSStringAttributeValue): 
    266313    """ElementTree XML representation of SAML String type Attribute Value"""  
    267314     
     
    288335        elem.set("%s:%s" % (SAMLConstants.XSI_PREFIX, 'type'),  
    289336                 "%s:%s" % (SAMLConstants.XSD_PREFIX,  
    290                             XSStringAttributeValue.TYPE_LOCAL_NAME)) 
     337                            cls.TYPE_LOCAL_NAME)) 
    291338 
    292339        elem.text = attributeValue.value 
     
    309356 
    310357        localName = getLocalName(elem) 
    311         if localName != XSStringAttributeValue.DEFAULT_ELEMENT_LOCAL_NAME: 
     358        if localName != cls.DEFAULT_ELEMENT_LOCAL_NAME: 
    312359            raise XMLObjectParseError("No \"%s\" element found" % 
    313                             XSStringAttributeValue.DEFAULT_ELEMENT_LOCAL_NAME) 
     360                                      cls.DEFAULT_ELEMENT_LOCAL_NAME) 
    314361         
    315362        # Parse the attribute type checking that it is set to the expected  
     
    319366        typeValue = elem.attrib.get(str(typeQName), '') 
    320367        typeValueLocalName = typeValue.split(':')[-1] 
    321         if typeValueLocalName != XSStringAttributeValue.TYPE_LOCAL_NAME: 
     368        if typeValueLocalName != cls.TYPE_LOCAL_NAME: 
    322369            raise XMLObjectParseError('Expecting "%s" type; got "%s"' % 
    323                                       (XSStringAttributeValue.TYPE_LOCAL_NAME, 
    324                                        type)) 
     370                                      (cls.TYPE_LOCAL_NAME, 
     371                                       typeValueLocalName)) 
    325372         
    326373        # Update namespace map as an XSI type has been referenced.  This will 
     
    336383 
    337384 
    338 class XSGroupRoleAttributeValueElementTree(AttributeValueElementTreeBase): 
     385class XSGroupRoleAttributeValueElementTree(AttributeValueElementTreeBase, 
     386                                           XSGroupRoleAttributeValue): 
    339387    """ElementTree XML representation of Earth System Grid custom Group/Role  
    340388    Attribute Value"""  
     
    347395        if not isinstance(attributeValue, XSGroupRoleAttributeValue): 
    348396            raise TypeError("Expecting %r type; got: %r" %  
    349                             (XSGroupRoleAttributeValue, attributeValue)) 
     397                            (XSGroupRole, type(attributeValue))) 
    350398             
    351399        ElementTree._namespace_map[attributeValue.namespaceURI 
    352400                                   ] = attributeValue.namespacePrefix 
    353401         
    354         elem.set(XSGroupRoleAttributeValue.GROUP_ATTRIB_NAME,  
    355                  attributeValue.group) 
    356          
    357         elem.set(XSGroupRoleAttributeValue.ROLE_ATTRIB_NAME,  
    358                  attributeValue.role) 
     402        elem.set(cls.GROUP_ATTRIB_NAME, attributeValue.group) 
     403        elem.set(cls.ROLE_ATTRIB_NAME, attributeValue.role) 
    359404 
    360405        return elem 
     
    401446 
    402447        self.__idMap = AttributeValueElementTreeFactory.idMap 
    403         for samlId, etreeClass in customClassMap.items():  
     448        for samlId, etreeClass in customIdMap.items():  
    404449            if not isinstance(samlId, basestring): 
    405450                raise TypeError("Input custom SAML identifier must be a " 
     
    433478        else: 
    434479            raise TypeError("Expecting %r class got %r" % (AttributeValue,  
    435                                                            type(samlObject))) 
     480                                                           type(input))) 
    436481             
    437482             
     
    439484 
    440485         
    441 class IssuerElementTree(SAMLElementTree): 
     486class IssuerElementTree(SAMLElementTree, Issuer): 
    442487    """Represent a SAML Issuer element in XML using ElementTree""" 
    443488     
     
    446491        """Create an XML representation of the input SAML issuer object""" 
    447492        if not isinstance(issuer, Issuer): 
    448             raise TypeError("Expecting %r class got %r" % (issuer,  
    449                                                            type(Issuer))) 
     493            raise TypeError("Expecting %r class got %r" % (Issuer,  
     494                                                           type(issuer))) 
    450495        attrib = { 
    451             Issuer.FORMAT_ATTRIB_NAME: issuer.format 
     496            cls.FORMAT_ATTRIB_NAME: issuer.format 
    452497        } 
    453         elem = ElementTree.Element(str(Issuer.DEFAULT_ELEMENT_NAME), **attrib) 
     498        elem = ElementTree.Element(str(cls.DEFAULT_ELEMENT_NAME), **attrib) 
    454499        ElementTree._namespace_map[issuer.qname.namespaceURI 
    455500                                   ] = issuer.qname.prefix 
     
    466511                            (ElementTree.Element, elem)) 
    467512 
    468         if getLocalName(elem) != Issuer.DEFAULT_ELEMENT_LOCAL_NAME: 
    469             raise XMLObjectParseError("No \"%s\" element found" % 
    470                                         Issuer.DEFAULT_ELEMENT_LOCAL_NAME) 
    471              
    472         issuerFormat = elem.attrib.get(Issuer.FORMAT_ATTRIB_NAME) 
     513        if getLocalName(elem) != cls.DEFAULT_ELEMENT_LOCAL_NAME: 
     514            raise XMLObjectParseError('No "%s" element found' % 
     515                                      cls.DEFAULT_ELEMENT_LOCAL_NAME) 
     516             
     517        issuerFormat = elem.attrib.get(cls.FORMAT_ATTRIB_NAME) 
    473518        if issuerFormat is None: 
    474519            raise XMLObjectParseError('No "%s" attribute found in "%s" ' 
    475520                                        'element' % 
    476521                                        (issuerFormat, 
    477                                          Issuer.DEFAULT_ELEMENT_LOCAL_NAME)) 
     522                                         cls.DEFAULT_ELEMENT_LOCAL_NAME)) 
    478523        issuer = Issuer() 
    479524        issuer.format = issuerFormat 
     
    481526         
    482527        return issuer 
    483          
    484 class NameIdElementTree(SAMLElementTree): 
     528 
     529         
     530class NameIdElementTree(SAMLElementTree, NameID): 
    485531    """Represent a SAML Name Identifier in XML using ElementTree""" 
    486532     
     
    495541         
    496542        if not isinstance(nameID, NameID): 
    497             raise TypeError("Expecting %r class got %r" % (nameID,  
    498                                                            type(NameID))) 
     543            raise TypeError("Expecting %r class got %r" % (NameID,  
     544                                                           type(nameID))) 
    499545        attrib = { 
    500             NameID.FORMAT_ATTRIB_NAME: nameID.format 
     546            cls.FORMAT_ATTRIB_NAME: nameID.format 
    501547        } 
    502         elem = ElementTree.Element(str(NameID.DEFAULT_ELEMENT_NAME), 
    503                                          **attrib) 
     548        elem = ElementTree.Element(str(cls.DEFAULT_ELEMENT_NAME), **attrib) 
    504549         
    505550        ElementTree._namespace_map[nameID.qname.namespaceURI 
     
    523568                            (ElementTree.Element, elem)) 
    524569 
    525         if getLocalName(elem) != NameID.DEFAULT_ELEMENT_LOCAL_NAME: 
     570        if getLocalName(elem) != cls.DEFAULT_ELEMENT_LOCAL_NAME: 
    526571            raise XMLObjectParseError("No \"%s\" element found" % 
    527                                         NameID.DEFAULT_ELEMENT_LOCAL_NAME) 
     572                                      cls.DEFAULT_ELEMENT_LOCAL_NAME) 
    528573             
    529574        format = elem.attrib.get(NameID.FORMAT_ATTRIB_NAME) 
    530575        if format is None: 
    531576            raise XMLObjectParseError('No "%s" attribute found in "%s" ' 
    532                                         'element' % 
    533                                         (format, 
    534                                          NameID.DEFAULT_ELEMENT_LOCAL_NAME)) 
     577                                      'element' % 
     578                                      (format, 
     579                                       cls.DEFAULT_ELEMENT_LOCAL_NAME)) 
    535580        nameID = NameID() 
    536581        nameID.format = format 
     
    540585 
    541586 
    542 class SubjectElementTree(SAMLElementTree): 
     587class SubjectElementTree(SAMLElementTree, Subject): 
    543588    """Represent a SAML Subject in XML using ElementTree""" 
    544589     
     
    552597        """ 
    553598        if not isinstance(subject, Subject): 
    554             raise TypeError("Expecting %r class got %r" % (subject,  
    555                                                            type(Subject))) 
     599            raise TypeError("Expecting %r class got %r" % (Subject,  
     600                                                           type(subject))) 
    556601             
    557602        elem = ElementTree.Element(str(Subject.DEFAULT_ELEMENT_NAME)) 
    558603         
    559         ElementTree._namespace_map[ 
    560             AttributeQuery.DEFAULT_ELEMENT_NAME.namespaceURI 
    561         ] = AttributeQuery.DEFAULT_ELEMENT_NAME.prefix 
    562  
    563              
    564         nameIdElementTree = NameIdElementTree() 
    565         nameIdElem = nameIdElementTree.create(subject.nameID) 
     604        ElementTree._namespace_map[cls.DEFAULT_ELEMENT_NAME.namespaceURI 
     605                                   ] = cls.DEFAULT_ELEMENT_NAME.prefix 
     606 
     607             
     608        nameIdElem = NameIdElementTree.create(subject.nameID) 
    566609        elem.append(nameIdElem) 
    567610         
     
    581624                            (ElementTree.Element, elem)) 
    582625 
    583         if getLocalName(elem) != Subject.DEFAULT_ELEMENT_LOCAL_NAME: 
     626        if getLocalName(elem) != cls.DEFAULT_ELEMENT_LOCAL_NAME: 
    584627            raise XMLObjectParseError("No \"%s\" element found" % 
    585                                         Subject.DEFAULT_ELEMENT_LOCAL_NAME) 
     628                                      cls.DEFAULT_ELEMENT_LOCAL_NAME) 
    586629             
    587630        if len(elem) != 1: 
     
    593636         
    594637        return subject 
    595      
    596      
    597 class AttributeQueryElementTree(SAMLElementTree, IssueInstantXMLObject): 
     638 
     639         
     640class StatusCodeElementTree(StatusCode): 
     641    """Represent a SAML Name Identifier in XML using ElementTree""" 
     642     
     643    @classmethod 
     644    def create(cls, statusCode): 
     645        """Create an XML representation of the input SAML Name Status Code 
     646         
     647        @type statusCode: ndg.security.common.saml.StatusCode 
     648        @param statusCode: SAML Status Code 
     649        @rtype: ElementTree.Element 
     650        @return: Status Code as ElementTree XML element""" 
     651         
     652        if not isinstance(statusCode, StatusCode): 
     653            raise TypeError("Expecting %r class got %r" % (StatusCode,  
     654                                                           type(statusCode))) 
     655 
     656        elem = ElementTree.Element(str(cls.DEFAULT_ELEMENT_NAME)) 
     657         
     658        ElementTree._namespace_map[statusCode.qname.namespaceURI 
     659                                   ] = statusCode.qname.prefix 
     660         
     661        elem.text = statusCode.value 
     662 
     663        return elem 
     664 
     665    @classmethod 
     666    def parse(cls, elem): 
     667        """Parse ElementTree element into a SAML StatusCode object 
     668         
     669        @type elem: ElementTree.Element 
     670        @param elem: Status Code as ElementTree XML element 
     671        @rtype: ndg.security.common.saml.StatusCode 
     672        @return: SAML Status Code 
     673        """ 
     674        if not ElementTree.iselement(elem): 
     675            raise TypeError("Expecting %r input type for parsing; got %r" % 
     676                            (ElementTree.Element, elem)) 
     677 
     678        if getLocalName(elem) != cls.DEFAULT_ELEMENT_LOCAL_NAME: 
     679            raise XMLObjectParseError('No "%s" element found' % 
     680                                      cls.DEFAULT_ELEMENT_LOCAL_NAME) 
     681             
     682        statusCode = StatusCode() 
     683        statusCode.format = format 
     684        statusCode.value = elem.text.strip()  
     685         
     686        return statusCode 
     687 
     688 
     689class StatusElementTree(Status): 
     690    """Represent a SAML Status in XML using ElementTree""" 
     691     
     692    @classmethod 
     693    def create(cls, status): 
     694        """Create an XML representation of the input SAML subject object 
     695        @type subject: ndg.security.common.saml.Status 
     696        @param subject: SAML subject 
     697        @rtype: ElementTree.Element 
     698        @return: subject as ElementTree XML element 
     699        """ 
     700        if not isinstance(status, Status): 
     701            raise TypeError("Expecting %r class got %r" % (status,  
     702                                                           type(Status))) 
     703             
     704        elem = ElementTree.Element(str(Status.DEFAULT_ELEMENT_NAME)) 
     705         
     706        ElementTree._namespace_map[cls.DEFAULT_ELEMENT_NAME.namespaceURI 
     707                                   ] = cls.DEFAULT_ELEMENT_NAME.prefix 
     708         
     709        statusCodeElem = StatusCodeElementTree.create(status.statusCode) 
     710        elem.append(statusCodeElem) 
     711         
     712        return elem 
     713 
     714    @classmethod 
     715    def parse(cls, elem): 
     716        """Parse ElementTree element into a SAML Status object 
     717         
     718        @type elem: ElementTree.Element 
     719        @param elem: subject as ElementTree XML element 
     720        @rtype: ndg.security.common.saml.Status 
     721        @return: SAML subject 
     722        """ 
     723        if not ElementTree.iselement(elem): 
     724            raise TypeError("Expecting %r input type for parsing; got %r" % 
     725                            (ElementTree.Element, elem)) 
     726 
     727        if getLocalName(elem) != Status.DEFAULT_ELEMENT_LOCAL_NAME: 
     728            raise XMLObjectParseError('No "%s" element found' % 
     729                                      Status.DEFAULT_ELEMENT_LOCAL_NAME) 
     730             
     731        if len(elem) != 1: 
     732            raise XMLObjectParseError("Expecting single StatusCode child " 
     733                                      "element for SAML Status element") 
     734             
     735        status = Status() 
     736        status.statusCode = StatusCodeElementTree.parse(elem[0]) 
     737         
     738        return status 
     739     
     740     
     741class AttributeQueryElementTree(AttributeQuery, IssueInstantXMLObject): 
    598742    """Represent a SAML Attribute Query in XML using ElementTree""" 
    599     def __init__(self): 
    600         SAMLElementTree.__init__(self) 
    601         IssueInstantXMLObject.__init__(self) 
    602743         
    603744    @classmethod 
     
    618759             
    619760         
    620         issueInstant = AttributeQueryElementTree.datetime2Str( 
    621                                                 attributeQuery.issueInstant) 
     761        issueInstant = cls.datetime2Str(attributeQuery.issueInstant) 
    622762        attrib = { 
    623             AttributeQuery.ID_ATTRIB_NAME: attributeQuery.id, 
    624             AttributeQuery.ISSUE_INSTANT_ATTRIB_NAME: issueInstant, 
     763            cls.ID_ATTRIB_NAME: attributeQuery.id, 
     764            cls.ISSUE_INSTANT_ATTRIB_NAME: issueInstant, 
    625765             
    626766            # Nb. Version is a SAMLVersion instance and requires explicit cast 
    627             AttributeQuery.VERSION_ATTRIB_NAME: str(attributeQuery.version) 
     767            cls.VERSION_ATTRIB_NAME: str(attributeQuery.version) 
    628768        } 
    629769                  
    630         elem = ElementTree.Element(str(AttributeQuery.DEFAULT_ELEMENT_NAME), 
    631                                    **attrib) 
    632          
    633         ElementTree._namespace_map[ 
    634             AttributeQuery.DEFAULT_ELEMENT_NAME.namespaceURI 
    635         ] = AttributeQuery.DEFAULT_ELEMENT_NAME.prefix 
    636          
    637              
    638         issuerElementTree = IssuerElementTree() 
    639         issuerElem = issuerElementTree.create(attributeQuery.issuer) 
     770        elem = ElementTree.Element(str(cls.DEFAULT_ELEMENT_NAME), **attrib) 
     771         
     772        ElementTree._namespace_map[cls.DEFAULT_ELEMENT_NAME.namespaceURI 
     773                                   ] = cls.DEFAULT_ELEMENT_NAME.prefix 
     774         
     775        issuerElem = IssuerElementTree.create(attributeQuery.issuer) 
    640776        elem.append(issuerElem) 
    641777 
    642         subjectElementTree = SubjectElementTree() 
    643         subjectElem = subjectElementTree.create(attributeQuery.subject) 
    644          
     778        subjectElem = SubjectElementTree.create(attributeQuery.subject) 
    645779        elem.append(subjectElem) 
    646  
    647         attributeElementTree = AttributeElementTree() 
    648780 
    649781        for attribute in attributeQuery.attributes: 
    650782            # Factory enables support for multiple attribute types 
    651             attributeElem = attributeElementTree.create(attribute, 
     783            attributeElem = AttributeElementTree.create(attribute, 
    652784                                        **attributeValueElementTreeFactoryKw) 
    653785            elem.append(attributeElem) 
     
    668800                            (ElementTree.Element, elem)) 
    669801 
    670         if getLocalName(elem) != AttributeQuery.DEFAULT_ELEMENT_LOCAL_NAME: 
     802        if getLocalName(elem) != cls.DEFAULT_ELEMENT_LOCAL_NAME: 
    671803            raise XMLObjectParseError("No \"%s\" element found" % 
    672                                     AttributeQuery.DEFAULT_ELEMENT_LOCAL_NAME) 
     804                                    cls.DEFAULT_ELEMENT_LOCAL_NAME) 
    673805         
    674806        # Unpack attributes from top-level element 
    675807        attributeValues = [] 
    676         for attributeName in (AttributeQuery.VERSION_ATTRIB_NAME, 
    677                               AttributeQuery.ISSUE_INSTANT_ATTRIB_NAME, 
    678                               AttributeQuery.ID_ATTRIB_NAME): 
     808        for attributeName in (cls.VERSION_ATTRIB_NAME, 
     809                              cls.ISSUE_INSTANT_ATTRIB_NAME, 
     810                              cls.ID_ATTRIB_NAME): 
    679811            attributeValue = elem.attrib.get(attributeName) 
    680812            if attributeValue is None: 
     
    682814                                 'element' % 
    683815                                 (attributeName, 
    684                                   AttributeQuery.DEFAULT_ELEMENT_LOCAL_NAME)) 
     816                                  cls.DEFAULT_ELEMENT_LOCAL_NAME)) 
    685817                 
    686818            attributeValues.append(attributeValue) 
     
    717849         
    718850        return attributeQuery 
     851         
     852     
     853class ResponseElementTree(Response, IssueInstantXMLObject): 
     854    """Represent a SAML Response in XML using ElementTree""" 
     855         
     856    @classmethod 
     857    def create(cls,  
     858               response,  
     859               **attributeValueElementTreeFactoryKw): 
     860        """Create an XML representation of the input SAML Response 
     861        object 
     862 
     863        @type response: ndg.security.common.saml.Response 
     864        @param response: SAML Response 
     865        @rtype: ElementTree.Element 
     866        @return: Response as ElementTree XML element 
     867        """ 
     868        if not isinstance(response, Response): 
     869            raise TypeError("Expecting %r class, got %r" % (Response,  
     870                                                            type(response))) 
     871             
     872         
     873        issueInstant = cls.datetime2Str(response.issueInstant) 
     874        attrib = { 
     875            cls.ID_ATTRIB_NAME: response.id, 
     876            cls.ISSUE_INSTANT_ATTRIB_NAME: issueInstant, 
     877            cls.IN_RESPONSE_TO_ATTRIB_NAME: response.inResponseTo, 
     878             
     879            # Nb. Version is a SAMLVersion instance and requires explicit cast 
     880            cls.VERSION_ATTRIB_NAME: str(response.version) 
     881        } 
     882                  
     883        elem = ElementTree.Element(str(cls.DEFAULT_ELEMENT_NAME), **attrib) 
     884         
     885        ElementTree._namespace_map[cls.DEFAULT_ELEMENT_NAME.namespaceURI 
     886                                   ] = cls.DEFAULT_ELEMENT_NAME.prefix 
     887             
     888        issuerElem = IssuerElementTree.create(response.issuer) 
     889        elem.append(issuerElem) 
     890 
     891        statusElem = StatusElementTree.create(response.status)        
     892        elem.append(statusElem) 
     893 
     894        for assertion in response.assertions: 
     895            # Factory enables support for multiple attribute types 
     896            assertionElem = AssertionElementTree.create(assertion, 
     897                                        **attributeValueElementTreeFactoryKw) 
     898            elem.append(assertionElem) 
     899         
     900        return elem 
     901 
     902    @classmethod 
     903    def parse(cls, elem): 
     904        """Parse ElementTree element into a SAML Response object 
     905         
     906        @type elem: ElementTree.Element 
     907        @param elem: XML element containing the Response 
     908        @rtype: ndg.security.common.saml.Response 
     909        @return: Response object 
     910        """ 
     911        if not ElementTree.iselement(elem): 
     912            raise TypeError("Expecting %r input type for parsing; got %r" % 
     913                            (ElementTree.Element, elem)) 
     914 
     915        if getLocalName(elem) != Response.DEFAULT_ELEMENT_LOCAL_NAME: 
     916            raise XMLObjectParseError("No \"%s\" element found" % 
     917                                    Response.DEFAULT_ELEMENT_LOCAL_NAME) 
     918         
     919        # Unpack attributes from top-level element 
     920        attributeValues = [] 
     921        for attributeName in (Response.VERSION_ATTRIB_NAME, 
     922                              Response.ISSUE_INSTANT_ATTRIB_NAME, 
     923                              Response.ID_ATTRIB_NAME, 
     924                              Response.IN_RESPONSE_TO_ATTRIB_NAME): 
     925            attributeValue = elem.attrib.get(attributeName) 
     926            if attributeValue is None: 
     927                raise XMLObjectParseError('No "%s" attribute found in "%s" ' 
     928                                          'element' % 
     929                                         (attributeName, 
     930                                          Response.DEFAULT_ELEMENT_LOCAL_NAME)) 
     931                 
     932            attributeValues.append(attributeValue) 
     933         
     934        response = Response() 
     935        response.version = SAMLVersion(attributeValues[0]) 
     936        if response.version != SAMLVersion.VERSION_20: 
     937            raise NotImplementedError("Parsing for %r is implemented for " 
     938                                      "SAML version %s only; version %s is "  
     939                                      "not supported" %  
     940                                      (cls, 
     941                                       SAMLVersion(SAMLVersion.VERSION_20), 
     942                                       SAMLVersion(response.version))) 
     943             
     944        response.issueInstant = cls.str2Datetime(attributeValues[1]) 
     945        response.id = attributeValues[2] 
     946        response.inResponseTo = attributeValues[3] 
     947         
     948        for childElem in elem: 
     949            localName = getLocalName(childElem) 
     950            if localName == Issuer.DEFAULT_ELEMENT_LOCAL_NAME: 
     951                # Parse Issuer 
     952                response.issuer = IssuerElementTree.parse(childElem) 
     953             
     954            elif localName == Status.DEFAULT_ELEMENT_LOCAL_NAME: 
     955                # Get status of response 
     956                response.status = StatusElementTree.parse(childElem) 
     957                 
     958            elif localName == Subject.DEFAULT_ELEMENT_LOCAL_NAME: 
     959                # Parse Subject 
     960                response.subject = SubjectElementTree.parse(childElem) 
     961             
     962            elif localName == Assertion.DEFAULT_ELEMENT_LOCAL_NAME: 
     963                response.assertions.append( 
     964                                        AssertionElementTree.parse(childElem)) 
     965            else: 
     966                raise XMLObjectParseError('Unrecognised Response child ' 
     967                                          'element "%s"' % localName) 
     968         
     969        return response 
     970 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/soap.py

    r5517 r5589  
    1515log = logging.getLogger(__name__) 
    1616 
    17 from ndg.security.common.utils import QName 
     17from ndg.security.common.utils.etree import QName 
    1818 
    1919class SOAPException(Exception): 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/soap/client.py

    r5528 r5589  
    1313from ndg.security.common.soap import SOAPEnvelopeBase 
    1414 
     15class HTTPException(Exception): 
     16    """Server returned HTTP code error code""" 
     17    def __init__(self, *arg, **kw): 
     18        Exception.__init__(self, *arg, **kw) 
     19        self.urllib2Response = None 
     20         
    1521class SOAPClientBase(object): 
    1622    """Handle client request to a SOAP Service""" 
     
    154160        soapRequestStr = soapRequest.envelope.serialize() 
    155161        soapResponse = UrlLib2SOAPResponse() 
    156         soapResponse.fileObject = self.openerDirector.open(soapRequest.url,  
    157                                                            soapRequestStr,  
    158                                                            *arg) 
     162        response = self.openerDirector.open(soapRequest.url,  
     163                                            soapRequestStr,  
     164                                            *arg) 
     165        if response.code != 200: 
     166            output = response.read() 
     167            excep = HTTPException("Response is: %d %s" % (response.code,  
     168                                                          response.msg)) 
     169            excep.urllib2Response = response 
     170            raise excep 
     171         
     172         
     173        soapResponse.fileObject = response 
    159174        soapResponse.envelope = self.responseEnvelopeClass()   
    160175        soapResponse.envelope.parse(soapResponse.fileObject) 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/soap/etree.py

    r5538 r5589  
    1919 
    2020# ElementTree helper functions 
    21 from ndg.security.common.utils import QName, canonicalize, getLocalName 
     21from ndg.security.common.utils.etree import QName, getLocalName 
    2222 
    2323from ndg.security.common.soap import SOAPObject, SOAPEnvelopeBase, \ 
     
    5252    qname = property(_getQname, _setQname, None, "Qualified name object") 
    5353    elem = property(_getElem, _setElem, None, "Root element") 
    54      
    55 #    @staticmethod 
    56 #    def _serialize(elem): 
    57 #        """Serialise element tree into string""" 
    58 #         
    59 #        # Make a basic check for the SOAP name space declaration, if the 
    60 #        # element is constructed from a call to ElementTree.parse it may not 
    61 #        # be present  
    62 #        namespaceDeclarationFound = False 
    63 #        soapElemNsDeclaration = ( 
    64 #            'xmlns:%s' % SOAPObject.ELEMENT_PREFIX,  
    65 #            SOAPObject.DEFAULT_NS 
    66 #        ) 
    67 #        if soapElemNsDeclaration[0] not in elem.attrib: 
    68 #            log.warning("No SOAP namespace declaration found - adding one in") 
    69 #            elem.set(*soapElemNsDeclaration) 
    70 #         
    71 #        return canonicalize(elem) 
    7254 
    7355    @staticmethod 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/utils/__init__.py

    r5560 r5589  
    99__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1010__revision__ = '$Id: $' 
    11 try: # python 2.5 
    12     from xml.etree import cElementTree, ElementTree 
    13 except ImportError: 
    14     # if you've installed it yourself it comes this way 
    15     import cElementTree, ElementTree 
    16  
    17 # Fred Lundh's customisation for C14N functionality - egg available from 
    18 # http://ndg.nerc.ac.uk/dist site 
    19 c14nWarning = ("Custom ElementC14N package is not installed, canonicalize " 
    20                "function is disabled") 
    21 try: 
    22     from elementtree import ElementC14N 
    23     elementC14nNotInstalled = False 
    24 except ImportError: 
    25     elementC14nNotInstalled = True 
    26     import warnings 
    27     warnings.warn(c14nWarning) 
    28      
    29 from cStringIO import StringIO 
    30  
    31 # ElementTree helpers   
    32 getNs = lambda elem: elem.tag.split('}')[0][1:] 
    33 getLocalName = lambda elem: elem.tag.rsplit('}',1)[-1] 
    34  
    35 class QName(ElementTree.QName): 
    36     """Extend ElementTree implementation for improved attribute access support 
    37     """  
    38     def __init__(self, namespaceURI, tag=None, prefix=None): 
    39         ElementTree.QName.__init__(self, namespaceURI, tag=tag) 
    40          
    41         if tag: 
    42             self.namespaceURI = namespaceURI 
    43             self.localPart = tag 
    44         else: 
    45             self.namespaceURI = QName.getNs(self.text) 
    46             self.localPart = QName.getLocalName(self.text) 
    47              
    48         self.prefix = prefix 
    49  
    50     @staticmethod 
    51     def getNs(tag): 
    52         return tag.split('}')[0][1:] 
    53  
    54     @staticmethod 
    55     def getLocalName(tag): 
    56         return tag.rsplit('}',1)[-1] 
    57      
    58     def _getPrefix(self): 
    59         return self.__prefix 
    60  
    61     def _setPrefix(self, value): 
    62         self.__prefix = value 
    63      
    64     prefix = property(_getPrefix, _setPrefix, None, "Prefix") 
    65  
    66     def _getLocalPart(self): 
    67         return self.__localPart 
    68      
    69     def _setLocalPart(self, value): 
    70         self.__localPart = value 
    71          
    72     localPart = property(_getLocalPart, _setLocalPart, None, "LocalPart") 
    73  
    74     def _getNamespaceURI(self): 
    75         return self.__namespaceURI 
    76  
    77     def _setNamespaceURI(self, value): 
    78         self.__namespaceURI = value 
    79    
    80     namespaceURI = property(_getNamespaceURI, _setNamespaceURI, None,  
    81                             "Namespace URI'") 
    82  
    83 def canonicalize(elem, **kw): 
    84     '''ElementTree based Canonicalization - See ElementC14N for keyword 
    85     info.  Also useful for pretty printing XML 
    86     @type elem: ElementTree.Element 
    87     @param elem: element to be canonicalized 
    88     @rtype: basestring 
    89     @return: canonicalised output 
    90     ''' 
    91     if elementC14nNotInstalled: 
    92         raise NotImplementedError(c14nWarning) 
    93      
    94     f = StringIO() 
    95     ElementC14N.write(ElementC14N.build_scoped_tree(elem), f, **kw) 
    96     return f.getvalue() 
    97  
    98 def prettyPrint(*arg, **kw): 
    99     '''Lightweight pretty printing of ElementTree elements''' 
    100      
    101     # Keep track of namespace declarations made so they're not repeated 
    102     declaredNss = [] 
    103      
    104     def estrip(elem): 
    105         ''' Just want to get rid of unwanted whitespace ''' 
    106         if elem is None: 
    107             return '' 
    108         else: 
    109             # just in case the elem is another simple type - e.g. int -  
    110             # wrapper it as a string 
    111             return str(elem).strip() 
    112  
    113     def _prettyPrint(elem, indent='', html=0, space=' '*4): 
    114         '''Most of the work done in this wrapped function - wrapped so that 
    115         state can be maintained for declared namespace declarations during 
    116         recursive calls using "declaredNss" above'''   
    117         strAttrib = ''.join([' %s="%s"' % (att, attVal)  
    118                              for att, attVal in elem.attrib.items()]) 
    119          
    120         namespace = getNs(elem) 
    121         nsPrefix = ElementTree._namespace_map.get(namespace) 
    122         if nsPrefix is None: 
    123             raise KeyError('prettyPrint: missing namespace "%s" for '  
    124                            'ElementTree._namespace_map' % namespace) 
    125              
    126         tag = "%s:%s" % (nsPrefix, getLocalName(elem)) 
    127          
    128         # Put in namespace declaration if one doesn't already exist 
    129         # FIXME: namespace declaration handling is wrong for handling child 
    130         # element scope 
    131         if namespace in declaredNss: 
    132             nsDeclaration = '' 
    133         else: 
    134             nsDeclaration = ' xmlns:%s="%s"' % (nsPrefix, namespace) 
    135             declaredNss.append(namespace) 
    136              
    137         result = '%s<%s%s%s>%s' % (indent, tag, nsDeclaration, strAttrib,  
    138                                    estrip(elem.text)) 
    139          
    140         children = len(elem) 
    141         if children: 
    142             result += ''.join(['\n'+ _prettyPrint(item, indent=indent+space)  
    143                                for item in elem]) + \ 
    144                     '\n%s%s</%s>' % (indent, estrip(item.tail), tag) 
    145         else: 
    146             result += '</%s>' % tag 
    147              
    148         return result 
    149      
    150     return _prettyPrint(*arg, **kw) 
    151  
    15211 
    15312class UniqList(list): 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/unit/attributeauthority/saml/test_samlinterface.py

    r5588 r5589  
    2525from ndg.security.common.saml.xml import XMLConstants 
    2626from ndg.security.common.saml.xml.etree import AssertionElementTree, \ 
    27     AttributeQueryElementTree 
     27    AttributeQueryElementTree, ResponseElementTree 
    2828     
    2929from ndg.security.common.soap.etree import SOAPEnvelope 
     
    5151        assertion.issueInstant = datetime.utcnow() 
    5252        assertion.attributeStatements.append(AttributeStatement()) 
    53           
     53        attributes = [] 
     54         
    5455        for attribute in attributeQuery.attributes: 
    5556            if attribute.name == "urn:esg:first:name": 
     
    9091                attributes.append(emailAddressAttribute) 
    9192                 
    92             assertion.attributeStatements[0].attributes.append(attribute) 
     93            assertion.attributeStatements[0].attributes = attributes 
    9394             
    9495        soapResponse = SOAPEnvelope() 
     
    184185        print("Parsed response ...") 
    185186        print(soapResponse.serialize()) 
    186          
    187  
     187       
     188    def test02AttributeQueryWithSOAPClient(self): 
     189        from ndg.security.common.soap.client import UrlLib2SOAPClient, \ 
     190            UrlLib2SOAPRequest 
     191             
     192        client = UrlLib2SOAPClient() 
     193         
     194        # ElementTree based envelope class 
     195        client.responseEnvelopeClass = SOAPEnvelope 
     196         
     197        request = UrlLib2SOAPRequest() 
     198        request.url = \ 
     199        'https://esg.prototype.ucar.edu/saml/soap/secure/attributeService.htm' 
     200        request.envelope = SOAPEnvelope() 
     201        request.envelope.create() 
     202         
     203        # Make an attribute query 
     204        attributeQuery = AttributeQuery() 
     205        attributeQuery.version = SAMLVersion(SAMLVersion.VERSION_20) 
     206        attributeQuery.id = str(uuid4()) 
     207        attributeQuery.issueInstant = datetime.utcnow() 
     208         
     209        attributeQuery.issuer = Issuer() 
     210        attributeQuery.issuer.format = Issuer.X509_SUBJECT 
     211        attributeQuery.issuer.value = \ 
     212                        "/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk" 
     213                         
     214                         
     215        attributeQuery.subject = Subject()   
     216        attributeQuery.subject.nameID = NameID() 
     217        attributeQuery.subject.nameID.format = "urn:esg:openid" 
     218        attributeQuery.subject.nameID.value = \ 
     219                            "https://esg.prototype.ucar.edu/myopenid/testUser" 
     220         
     221        # special case handling for 'FirstName' attribute 
     222        fnAttribute = Attribute() 
     223        fnAttribute.name = "urn:esg:first:name" 
     224        fnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string" 
     225        fnAttribute.friendlyName = "FirstName" 
     226 
     227        attributeQuery.attributes.append(fnAttribute) 
     228     
     229        # special case handling for 'LastName' attribute 
     230        lnAttribute = Attribute() 
     231        lnAttribute.name = "urn:esg:last:name" 
     232        lnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string" 
     233        lnAttribute.friendlyName = "LastName" 
     234 
     235        attributeQuery.attributes.append(lnAttribute) 
     236     
     237        # special case handling for 'LastName' attribute 
     238        emailAddressAttribute = Attribute() 
     239        emailAddressAttribute.name = "urn:esg:email:address" 
     240        emailAddressAttribute.nameFormat = XMLConstants.XSD_NS+"#"+\ 
     241                                    XSStringAttributeValue.TYPE_LOCAL_NAME 
     242        emailAddressAttribute.friendlyName = "emailAddress" 
     243 
     244        attributeQuery.attributes.append(emailAddressAttribute)                                    
     245         
     246        attributeQueryElem = AttributeQueryElementTree.create(attributeQuery) 
     247 
     248        # Attach query to SOAP body 
     249        request.envelope.body.elem.append(attributeQueryElem) 
     250         
     251        from M2Crypto.m2urllib2 import HTTPSHandler 
     252        from urllib2 import URLError 
     253 
     254        client.openerDirector.add_handler(HTTPSHandler()) 
     255        try: 
     256            response = client.send(request) 
     257        except URLError, e: 
     258            self.fail("Error calling Attribute Service") 
     259         
     260        print("Response from server:\n\n%s" % response.envelope.serialize()) 
     261         
     262        if len(response.envelope.body.elem) != 1: 
     263            self.fail("Expecting single child element is SOAP body") 
     264             
     265        if getLocalName(response.envelope.body.elem[0]) != 'Response': 
     266            self.fail('Expecting "Response" element in SOAP body') 
     267             
     268        response = ResponseElementTree.parse(response.envelope.body.elem[0]) 
     269             
    188270if __name__ == "__main__": 
    189271    unittest.main()         
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/unit/saml/test_saml.py

    r5588 r5589  
    1212logging.basicConfig(level=logging.DEBUG) 
    1313     
    14 from datetime import datetime 
     14from datetime import datetime, timedelta 
    1515from uuid import uuid4 
    1616from cStringIO import StringIO 
     
    2020from xml.etree.ElementTree import iselement 
    2121from xml.etree import ElementTree 
     22from ndg.security.common.utils.etree import prettyPrint 
    2223 
    2324from ndg.security.common.saml import Assertion, Attribute, AttributeValue, \ 
    2425    AttributeStatement, SAMLVersion, XSStringAttributeValue, \ 
    25     XSGroupRoleAttributeValue, AttributeQuery, Issuer, Subject, NameID 
     26    XSGroupRoleAttributeValue, AttributeQuery, Response, Issuer, Subject, \ 
     27    NameID, StatusCode, Status, Conditions 
    2628from ndg.security.common.saml.xml import XMLConstants 
    2729from ndg.security.common.saml.xml.etree import AssertionElementTree, \ 
    28     XSGroupRoleAttributeValueElementTree, AttributeQueryElementTree 
     30    XSGroupRoleAttributeValueElementTree, AttributeQueryElementTree, \ 
     31    ResponseElementTree, ConditionsElementTree 
    2932 
    3033 
     
    7578        assertion.id = str(uuid4()) 
    7679        assertion.issueInstant = datetime.utcnow() 
    77  
    7880        attributeStatement = AttributeStatement() 
    7981         
     
    8183            attributeStatement.attributes.append(attribute) 
    8284             
     85        assertion.attributeStatements.append(attributeStatement) 
     86         
    8387        return assertion 
    8488 
     
    181185    """Test SAML implementation for use with CMIP5 federation""" 
    182186     
    183     def test01CreateAssertion(self): 
     187    def _createAssertionHelper(self): 
    184188        samlUtil = SAMLUtil() 
    185189         
     
    211215        # Make an assertion object 
    212216        assertion = samlUtil.buildAssertion() 
    213                  
     217         
     218        return assertion 
     219         
     220    def test01CreateAssertion(self): 
     221          
     222        assertion = self._createAssertionHelper() 
     223         
    214224        # Add mapping for ESG Group/Role Attribute Value to enable ElementTree 
    215225        # Attribute Value factory to render the XML output 
     
    225235         
    226236        # Serialise to output 
    227         xmlOutput = AssertionElementTree.prettyPrint(assertionElem) 
     237        xmlOutput = prettyPrint(assertionElem) 
    228238        self.assert_(len(xmlOutput)) 
    229239        print(xmlOutput) 
     
    239249         
    240250        elem = AttributeQueryElementTree.create(attributeQuery) 
    241         xmlOutput = AttributeQueryElementTree.prettyPrint(elem) 
     251        xmlOutput = prettyPrint(elem) 
    242252        print(xmlOutput) 
    243253 
     
    252262         
    253263        elem = AttributeQueryElementTree.create(attributeQuery) 
    254 #        xmlOutput = AttributeQueryElementTree.prettyPrint(elem) 
    255         xmlOutput = AttributeQueryElementTree.serialize(elem) 
     264        xmlOutput = prettyPrint(elem) 
    256265        print(xmlOutput) 
    257266                 
     
    267276        self.assert_(attributeQuery2.issuer.value==attributeQuery.issuer.value) 
    268277        self.assert_(attributeQuery2.subject.nameID.value == \ 
    269                      attributeQuery.nameID.value) 
     278                     attributeQuery.subject.nameID.value) 
    270279         
    271280        self.assert_(attributeQuery2.attributes[1].name == \ 
    272281                     attributeQuery.attributes[1].name) 
    273282         
    274         xmlOutput2 = AttributeQueryElementTree.serialize(elem2) 
     283        xmlOutput2 = prettyPrint(elem2) 
    275284        print(xmlOutput2) 
    276285 
    277          
    278          
     286    def test04createResponse(self): 
     287        response = Response() 
     288        response.issueInstant = datetime.utcnow() 
     289         
     290        # Make up a request ID that this response is responding to 
     291        response.inResponseTo = str(uuid4()) 
     292        response.id = str(uuid4()) 
     293        response.version = SAMLVersion(SAMLVersion.VERSION_20) 
     294             
     295        response.issuer = Issuer() 
     296        response.issuer.format = Issuer.X509_SUBJECT 
     297        response.issuer.value = \ 
     298                        "/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk" 
     299         
     300        response.status = Status() 
     301        response.status.statusCode = StatusCode() 
     302        response.status.statusCode.value = StatusCode.SUCCESS_URI         
     303                 
     304        assertion = self._createAssertionHelper() 
     305         
     306        # Add a conditions statement for a validity of 8 hours 
     307        assertion.conditions = Conditions() 
     308        assertion.conditions.notBefore = datetime.utcnow() 
     309        assertion.conditions.notOnOrAfter = assertion.conditions.notBefore + \ 
     310            timedelta(seconds=60*60*8) 
     311         
     312        assertion.subject = Subject()   
     313        assertion.subject.nameID = NameID() 
     314        assertion.subject.nameID.format = "urn:esg:openid" 
     315        assertion.subject.nameID.value = \ 
     316                        "https://openid.localhost/philip.kershaw"     
     317             
     318        assertion.issuer = Issuer() 
     319        assertion.issuer.format = Issuer.X509_SUBJECT 
     320        assertion.issuer.value = \ 
     321                        "/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk" 
     322 
     323        response.assertions.append(assertion) 
     324         
     325        # Add mapping for ESG Group/Role Attribute Value to enable ElementTree 
     326        # Attribute Value factory to render the XML output 
     327        attributeValueElementTreeClassMap = { 
     328            XSGroupRoleAttributeValue: XSGroupRoleAttributeValueElementTree            
     329        } 
     330         
     331        # Create ElementTree Assertion Element 
     332        responseElem = ResponseElementTree.create(response, 
     333                            customClassMap=attributeValueElementTreeClassMap) 
     334         
     335        self.assert_(iselement(responseElem)) 
     336         
     337        # Serialise to output 
     338        xmlOutput = prettyPrint(responseElem) 
     339        self.assert_(len(xmlOutput)) 
     340        print(xmlOutput) 
     341     
    279342if __name__ == "__main__": 
    280343    unittest.main()         
Note: See TracChangeset for help on using the changeset viewer.