def isValidCredential(self, assertion):
     """Validate SAML assertion time validity"""
     utcNow = datetime.utcnow()
     if utcNow < assertion.conditions.notBefore - self.clockSkewTolerance:
         msg = ('The current clock time [%s] is before the SAML Attribute '
                'Response assertion conditions not before time [%s] ' 
                '(with clock skew tolerance = %s)' % 
                (SAMLDateTime.toString(utcNow),
                 assertion.conditions.notBefore,
                 self.clockSkewTolerance))
         log.warning(msg)
         return False
         
     if (utcNow >= 
         assertion.conditions.notOnOrAfter + self.clockSkewTolerance):
         msg = ('The current clock time [%s] is on or after the SAML '
                'Attribute Response assertion conditions not on or after '
                'time [%s] (with clock skew tolerance = %s)' % 
                (SAMLDateTime.toString(utcNow),
                 assertion.conditions.notOnOrAfter,
                 self.clockSkewTolerance))
         log.warning(msg)
         return False
         
     return True
 def test03ParseResponse(self):
     utcNow = datetime.utcnow()
     respDict = {
         'issueInstant': SAMLDateTime.toString(utcNow),
         'assertionIssueInstant': SAMLDateTime.toString(utcNow),
         'notBefore': SAMLDateTime.toString(utcNow),
         'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta(
                                                         seconds=60*60*8))
     }
     responseStr = self.__class__.RESPONSE % respDict
     response = self._parseResponse(responseStr)
     self.assert_(response)
 def _verifyQueryTimeConditions(self, query, response):
     """Checking incoming query issue instant
     :type query: saml.saml2.core.SubjectQuery 
     :param query: SAML subject query to be checked
     :type: saml.saml2.core.Response
     :param: SAML Response 
     :raise QueryIssueInstantInvalid: for invalid issue instant
     """
     if not self.verifyTimeConditions: 
         log.debug("Skipping verification of SAML query time conditions")
         return
           
     utcNow = datetime.utcnow() 
     nowPlusSkew = utcNow + self.clockSkewTolerance
     
     if query.issueInstant > nowPlusSkew:
         msg = ('SAML Attribute Query issueInstant [%s] is after '
                'the clock time [%s] (skewed +%s)' % 
                (query.issueInstant, 
                 SAMLDateTime.toString(nowPlusSkew),
                 self.clockSkewTolerance))
          
         samlRespError = QueryIssueInstantInvalid(msg)
         samlRespError.response = response
         raise samlRespError
    def fromXML(cls, elem):
        """Parse ElementTree element into a SAML XACMLAuthzDecisionQuery object
        
        @type elem: ElementTree.Element
        @param elem: XML element containing the AuthzDecisionQuery
        @rtype: saml.saml2.core.AuthzDecisionQuery
        @return: AuthzDecisionQuery object
        """
        if not ElementTree.iselement(elem):
            raise TypeError("Expecting %r input type for parsing; got %r" %
                            (ElementTree.Element, elem))

        if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
            raise XMLTypeParseError("No \"%s\" element found" %
                                    cls.DEFAULT_ELEMENT_LOCAL_NAME)
        
        # Unpack attributes from top-level element
        attributeValues = []
        for attributeName in (cls.VERSION_ATTRIB_NAME,
                              cls.ISSUE_INSTANT_ATTRIB_NAME,
                              cls.ID_ATTRIB_NAME):
            attributeValue = elem.attrib.get(attributeName)
            if attributeValue is None:
                raise XMLTypeParseError('No "%s" attribute found in "%s" '
                                 'element' %
                                 (attributeName,
                                  cls.DEFAULT_ELEMENT_LOCAL_NAME))
                
            attributeValues.append(attributeValue)
        
        authzDecisionQuery = XACMLAuthzDecisionQuery()
        authzDecisionQuery.version = SAMLVersion(attributeValues[0])
        if authzDecisionQuery.version != SAMLVersion.VERSION_20:
            raise NotImplementedError("Parsing for %r is implemented for "
                                      "SAML version %s only; version %s is " 
                                      "not supported" % 
                                      (cls,
                                       SAMLVersion(SAMLVersion.VERSION_20),
                                       SAMLVersion(authzDecisionQuery.version)))
            
        authzDecisionQuery.issueInstant = SAMLDateTime.fromString(
                                                            attributeValues[1])
        authzDecisionQuery.id = attributeValues[2]
        
        for childElem in elem:
            localName = QName.getLocalPart(childElem.tag)
            if localName == Issuer.DEFAULT_ELEMENT_LOCAL_NAME:
                # Parse Issuer
                authzDecisionQuery.issuer = IssuerElementTree.fromXML(childElem)

            elif localName == Request.ELEMENT_LOCAL_NAME:
                # Create XACML context request from Request element.
                authzDecisionQuery.xacmlContextRequest = \
                    RequestElementTree.fromXML(childElem)

            else:
                raise XMLTypeParseError("Unrecognised XACMLAuthzDecisionQuery child "
                                        "element \"%s\"" % localName)
        
        return authzDecisionQuery
 def test06NotBeforeConditionInvalid(self):
     utcNow = datetime.utcnow()
     respDict = {
         'issueInstant': SAMLDateTime.toString(utcNow),
         'assertionIssueInstant': SAMLDateTime.toString(utcNow),
         'notBefore': SAMLDateTime.toString(utcNow + timedelta(seconds=1)),
         'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta(
                                                         seconds=60*60*8))
     }
     responseStr = self.__class__.RESPONSE % respDict
     response = self._parseResponse(responseStr)
     binding = SubjectQuerySOAPBinding()
     try:
         binding._verifyTimeConditions(response)
         self.fail("Expecting issue instant timestamp error")
     except AssertionConditionNotBeforeInvalid, e:
         print("PASSED: %s" % e)
Exemple #6
0
 def test17SAMLDatetime(self):
     # Test parsing of Datetimes following 
     # http://www.w3.org/TR/xmlschema-2/#dateTime 
     
     # No seconds fraction
     self.assertTrue(SAMLDateTime.fromString('2010-10-20T14:49:50Z'))
     
     self.assertRaises(TypeError, SAMLDateTime.fromString, None)
 def test04AssertionConditionExpired(self):
     # issued 9 hours ago
     issueInstant = datetime.utcnow() - timedelta(seconds=60*60*9)
     respDict = {
         'issueInstant': SAMLDateTime.toString(issueInstant),
         'assertionIssueInstant': SAMLDateTime.toString(issueInstant),
         'notBefore': SAMLDateTime.toString(issueInstant),
         # It lasts for 8 hours so it's expired by one hour
         'notOnOrAfter': SAMLDateTime.toString(issueInstant + timedelta(
                                                         seconds=60*60*8))
     }
     responseStr = self.__class__.RESPONSE % respDict
     response = self._parseResponse(responseStr)
     binding = SubjectQuerySOAPBinding()
     try:
         binding._verifyTimeConditions(response)
         self.fail("Expecting not on or after timestamp error")
     except AssertionConditionNotOnOrAfterInvalid, e:
         print("PASSED: %s" % e)
    def _createAssertion(self, timeNow=None, validityDuration=60*60*8,
                         issuerName=BaseTestCase.SITEA_SAML_ISSUER_NAME):
        if timeNow is None:
            timeNow = datetime.utcnow()
            
        timeExpires = timeNow + timedelta(seconds=validityDuration)
        assertionStr = Template(
            self.__class__.ASSERTION_STR).substitute(
                dict(
                 issuerName=issuerName,
                 timeNow=SAMLDateTime.toString(timeNow), 
                 timeExpires=SAMLDateTime.toString(timeExpires)
                )
            )

        assertionStream = StringIO()
        assertionStream.write(assertionStr)
        assertionStream.seek(0)
        assertionElem = ElementTree.parse(assertionStream).getroot()
        return AssertionElementTree.fromXML(assertionElem)
 def test07ClockSkewCorrectedAssertionIssueInstantInvalid(self):
     utcNow = datetime.utcnow()
     respDict = {
         'issueInstant': SAMLDateTime.toString(utcNow),
         'assertionIssueInstant': SAMLDateTime.toString(utcNow + timedelta(
                                                                 seconds=1)),
         'notBefore': SAMLDateTime.toString(utcNow),
         'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta(
                                                         seconds=60*60*8))
     }
     responseStr = self.__class__.RESPONSE % respDict
     response = self._parseResponse(responseStr)
     binding = SubjectQuerySOAPBinding()
     
     # Set a skew to correct the error
     binding.clockSkewTolerance = 1
     
     try:
         binding._verifyTimeConditions(response)
     except AssertionIssueInstantInvalid, e:
         self.fail("issue instant timestamp error should be corrected for")
 def test08ClockSkewCorrectedAssertionConditionExpired(self):
     # Issued 9 hours ago
     issueInstant = datetime.utcnow() - timedelta(seconds=60*60*9)
     respDict = {
         'issueInstant': SAMLDateTime.toString(issueInstant),
         'assertionIssueInstant': SAMLDateTime.toString(issueInstant),
         'notBefore': SAMLDateTime.toString(issueInstant),
         # Assertion lasts 8 hours so it has expired by one hour
         'notOnOrAfter': SAMLDateTime.toString(issueInstant + timedelta(
                                                         seconds=60*60*8))
     }
     responseStr = self.__class__.RESPONSE % respDict
     response = self._parseResponse(responseStr)
     binding = SubjectQuerySOAPBinding()
     
     # Set a skew of over one hour to correct for the assertion expiry
     binding.clockSkewTolerance = 60*60 + 3
     
     try:
         binding._verifyTimeConditions(response)
         
     except AssertionConditionNotOnOrAfterInvalid:
         self.fail("Not on or after timestamp error should be corrected for")
    def toXML(cls, xacmlAuthzDecisionQuery):
        """Create an XML representation of the input SAML Authorization
        Decision Query object

        @type xacmlAuthzDecisionQuery: saml.saml2.core.AuthzDecisionQuery
        @param xacmlAuthzDecisionQuery: SAML Authorization Decision Query
        @rtype: ElementTree.Element
        @return: Attribute Query as ElementTree XML element
        """
        if not isinstance(xacmlAuthzDecisionQuery, XACMLAuthzDecisionQuery):
            raise TypeError("Expecting %r class got %r" % (XACMLAuthzDecisionQuery, 
                                                    type(xacmlAuthzDecisionQuery)))

        if not xacmlAuthzDecisionQuery.xacmlContextRequest:
            raise AttributeError("No xacmlContextRequest has been set for the "
                                 "XACMLAuthzDecisionQuery")

        issueInstant = SAMLDateTime.toString(xacmlAuthzDecisionQuery.issueInstant)
        attrib = {
            cls.ID_ATTRIB_NAME: xacmlAuthzDecisionQuery.id,
            cls.ISSUE_INSTANT_ATTRIB_NAME: issueInstant,

            # Nb. Version is a SAMLVersion instance and requires explicit cast
            cls.VERSION_ATTRIB_NAME: str(xacmlAuthzDecisionQuery.version),
        }

        tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
        elem = etree.makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
                                      cls.DEFAULT_ELEMENT_NAME.namespaceURI,
                                      **attrib)

        issuerElem = IssuerElementTree.toXML(xacmlAuthzDecisionQuery.issuer)
        elem.append(issuerElem)

        requestElem = RequestElementTree.toXML(
                                    xacmlAuthzDecisionQuery.xacmlContextRequest)
        elem.append(requestElem)

        return elem
Exemple #12
0
 def _verifyTimeConditions(self, response):
     """Verify time conditions set in a response
     :param response: SAML Response returned from remote service
     :type response: ndg.saml.saml2.core.Response
     :raise RequestResponseError: if a timestamp is invalid
     """
     
     if not self.verifyTimeConditions:
         log.debug("Skipping verification of SAML Response time conditions")
         
     utcNow = datetime.utcnow() 
     nowMinusSkew = utcNow - self.clockSkewTolerance
     nowPlusSkew = utcNow + self.clockSkewTolerance
     
     if response.issueInstant > nowPlusSkew:
         msg = ('SAML Attribute Response issueInstant [%s] is after '
                'the clock time [%s] (skewed +%s)' % 
                (response.issueInstant, 
                 SAMLDateTime.toString(nowPlusSkew),
                 self.clockSkewTolerance))
          
         samlRespError = ResponseIssueInstantInvalid(msg)
         samlRespError.response = response
         raise samlRespError
     
     for assertion in response.assertions:
         if assertion.issueInstant is None:
             samlRespError = AssertionIssueInstantInvalid("No issueInstant "
                                                          "set in response "
                                                          "assertion")
             samlRespError.response = response
             raise samlRespError
         
         elif nowPlusSkew < assertion.issueInstant:
             msg = ('The clock time [%s] (skewed +%s) is before the '
                    'SAML Attribute Response assertion issue instant [%s]' % 
                    (SAMLDateTime.toString(utcNow),
                     self.clockSkewTolerance,
                     assertion.issueInstant))
             samlRespError = AssertionIssueInstantInvalid(msg)
             samlRespError.response = response
             raise samlRespError
         
         if assertion.conditions is not None:
             if nowPlusSkew < assertion.conditions.notBefore:            
                 msg = ('The clock time [%s] (skewed +%s) is before the '
                        'SAML Attribute Response assertion conditions not '
                        'before time [%s]' % 
                        (SAMLDateTime.toString(utcNow),
                         self.clockSkewTolerance,
                         assertion.conditions.notBefore))
                           
                 samlRespError = AssertionConditionNotBeforeInvalid(msg)
                 samlRespError.response = response
                 raise samlRespError
              
             if nowMinusSkew >= assertion.conditions.notOnOrAfter:           
                 msg = ('The clock time [%s] (skewed -%s) is on or after '
                        'the SAML Attribute Response assertion conditions '
                        'not on or after time [%s]' % 
                        (SAMLDateTime.toString(utcNow),
                         self.clockSkewTolerance,
                         assertion.conditions.notOnOrAfter))
                 
                 samlRespError = AssertionConditionNotOnOrAfterInvalid(msg) 
                 samlRespError.response = response
                 raise samlRespError