def testIsInvalidDestination(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        Case Invalid Destination
        """
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html'
        }
        request = self.file_contents(
            join(self.data_path, 'logout_requests', 'logout_request.xml'))
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
        logout_request = OneLogin_Saml2_Logout_Request(
            settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        logout_request2 = OneLogin_Saml2_Logout_Request(
            settings, OneLogin_Saml2_Utils.b64encode(request))
        with self.assertRaisesRegexp(Exception,
                                     'The LogoutRequest was received at'):
            logout_request2.is_valid(request_data, raise_exceptions=True)

        dom = parseString(request)
        dom.documentElement.setAttribute('Destination', None)
        logout_request3 = OneLogin_Saml2_Logout_Request(
            settings, OneLogin_Saml2_Utils.b64encode(dom.toxml()))
        self.assertTrue(logout_request3.is_valid(request_data))

        dom.documentElement.removeAttribute('Destination')
        logout_request4 = OneLogin_Saml2_Logout_Request(
            settings, OneLogin_Saml2_Utils.b64encode(dom.toxml()))
        self.assertTrue(logout_request4.is_valid(request_data))
    def testIsInvalidIssuer(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        Case Invalid Issuer
        """
        request = self.file_contents(
            join(self.data_path, 'logout_requests', 'invalids',
                 'invalid_issuer.xml'))
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html'
        }
        current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data)
        request = request.replace(
            'http://stuff.com/endpoints/endpoints/sls.php', current_url)
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
        logout_request = OneLogin_Saml2_Logout_Request(
            settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        logout_request2 = OneLogin_Saml2_Logout_Request(
            settings, OneLogin_Saml2_Utils.b64encode(request))
        with self.assertRaisesRegex(Exception,
                                    'Invalid issuer in the Logout Request'):
            logout_request2.is_valid(request_data, raise_exceptions=True)
    def testIsInvalidDestination(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        Case Invalid Destination
        """
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html'
        }
        request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml'))
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
        logout_request = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        try:
            logout_request2 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
            valid = logout_request2.is_valid(request_data)
            self.assertFalse(valid)
        except Exception as e:
            self.assertIn('The LogoutRequest was received at', str(e))

        dom = parseString(request)
        dom.documentElement.setAttribute('Destination', None)
        logout_request3 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(dom.toxml()))
        self.assertTrue(logout_request3.is_valid(request_data))

        dom.documentElement.removeAttribute('Destination')
        logout_request4 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(dom.toxml()))
        self.assertTrue(logout_request4.is_valid(request_data))
Beispiel #4
0
    def testIsValid(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        """
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html'
        }
        request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml'))
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())

        logout_request = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        logout_request2 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertFalse(logout_request2.is_valid(request_data))

        settings.set_strict(False)
        dom = parseString(request)
        logout_request3 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(dom.toxml()))
        self.assertTrue(logout_request3.is_valid(request_data))

        settings.set_strict(True)
        logout_request4 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(dom.toxml()))
        self.assertFalse(logout_request4.is_valid(request_data))

        current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data)
        request = request.replace('http://stuff.com/endpoints/endpoints/sls.php', current_url)
        logout_request5 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request5.is_valid(request_data))
    def testIsValid(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        """
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html'
        }
        request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml'))
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())

        logout_request = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        logout_request2 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertFalse(logout_request2.is_valid(request_data))

        settings.set_strict(False)
        dom = parseString(request)
        logout_request3 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(dom.toxml()))
        self.assertTrue(logout_request3.is_valid(request_data))

        settings.set_strict(True)
        logout_request4 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(dom.toxml()))
        self.assertFalse(logout_request4.is_valid(request_data))

        current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data)
        request = request.replace('http://stuff.com/endpoints/endpoints/sls.php', current_url)
        logout_request5 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request5.is_valid(request_data))
    def testIsInvalidNotOnOrAfter(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        Case Invalid NotOnOrAfter
        """
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html'
        }
        request = self.file_contents(
            join(self.data_path, 'logout_requests', 'invalids',
                 'not_after_failed.xml'))
        current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data)
        request = request.replace(
            'http://stuff.com/endpoints/endpoints/sls.php', current_url)
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())

        logout_request = OneLogin_Saml2_Logout_Request(
            settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        try:
            logout_request2 = OneLogin_Saml2_Logout_Request(
                settings, OneLogin_Saml2_Utils.b64encode(request))
            valid = logout_request2.is_valid(request_data)
            self.assertFalse(valid)
        except Exception as e:
            self.assertIn('Timing issues (please check your clock settings)',
                          str(e))
    def testIsInvalidNotOnOrAfter(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        Case Invalid NotOnOrAfter
        """
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html'
        }
        request = self.file_contents(
            join(self.data_path, 'logout_requests', 'invalids',
                 'not_after_failed.xml'))
        current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data)
        request = request.replace(
            'http://stuff.com/endpoints/endpoints/sls.php', current_url)
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())

        logout_request = OneLogin_Saml2_Logout_Request(
            settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        logout_request2 = OneLogin_Saml2_Logout_Request(
            settings, OneLogin_Saml2_Utils.b64encode(request))
        with self.assertRaisesRegexp(
                Exception,
                'Could not validate timestamp: expired. Check system clock.'):
            logout_request2.is_valid(request_data, raise_exceptions=True)
    def testResponseAndAssertionSigned(self):
        """
        Tests the getNameId method of the OneLogin_Saml2_Response
        Case valid signed response, signed assertion
        """
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
        message = self.file_contents(join(self.data_path, 'responses', 'simple_saml_php.xml'))
        response = OneLogin_Saml2_Response(settings, OneLogin_Saml2_Utils.b64encode(message))

        self.assertEqual('*****@*****.**', response.get_nameid())
    def testResponseAndAssertionSigned(self):
        """
        Tests the getNameId method of the OneLogin_Saml2_Response
        Case valid signed response, signed assertion
        """
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
        message = self.file_contents(
            join(self.data_path, 'responses', 'simple_saml_php.xml'))
        response = OneLogin_Saml2_Response(
            settings, OneLogin_Saml2_Utils.b64encode(message))

        self.assertEqual('*****@*****.**', response.get_nameid())
Beispiel #10
0
 def _sign_saml_request(request, saml_auth, saml_security):
     sign_algorithm_transform_map = {
         OneLogin_Saml2_Constants.DSA_SHA1:
         xmlsec.constants.TransformDsaSha1,
         OneLogin_Saml2_Constants.RSA_SHA1:
         xmlsec.constants.TransformRsaSha1,
         OneLogin_Saml2_Constants.RSA_SHA256:
         xmlsec.constants.TransformRsaSha256,
         OneLogin_Saml2_Constants.RSA_SHA384:
         xmlsec.constants.TransformRsaSha384,
         OneLogin_Saml2_Constants.RSA_SHA512:
         xmlsec.constants.TransformRsaSha512
     }
     digest_algorithm_transform_map = {
         OneLogin_Saml2_Constants.SHA1: xmlsec.constants.TransformSha1,
         OneLogin_Saml2_Constants.SHA256: xmlsec.constants.TransformSha256,
         OneLogin_Saml2_Constants.SHA384: xmlsec.constants.TransformSha384,
         OneLogin_Saml2_Constants.SHA512: xmlsec.constants.TransformSha512
     }
     #
     request_root = etree.fromstring(request)
     xmlsec.tree.add_ids(request_root, ["ID"])
     signature_node = xmlsec.template.create(
         request_root, xmlsec.constants.TransformExclC14N,
         sign_algorithm_transform_map.get(
             saml_security.get("signatureAlgorithm",
                               OneLogin_Saml2_Constants.RSA_SHA1),
             xmlsec.constants.TransformRsaSha1))
     request_root.insert(1, signature_node)
     reference_node = xmlsec.template.add_reference(
         signature_node,
         digest_algorithm_transform_map.get(
             saml_security.get("digestAlgorithm",
                               OneLogin_Saml2_Constants.SHA1),
             xmlsec.constants.TransformSha1),
         uri=f"#{request_root.get('ID')}")
     xmlsec.template.add_transform(reference_node,
                                   xmlsec.constants.TransformEnveloped)
     xmlsec.template.add_transform(reference_node,
                                   xmlsec.constants.TransformExclC14N)
     xmlsec.template.add_x509_data(
         xmlsec.template.ensure_key_info(signature_node))
     signature_ctx = xmlsec.SignatureContext()
     signature_ctx.key = xmlsec.Key.from_memory(
         saml_auth.get_settings().get_sp_key(),
         xmlsec.constants.KeyDataFormatPem)
     signature_ctx.key.load_cert_from_memory(
         saml_auth.get_settings().get_sp_cert(),
         format=xmlsec.constants.KeyDataFormatPem)
     signature_ctx.sign(signature_node)
     request = OneLogin_Saml2_Utils.b64encode(etree.tostring(request_root))
     return request
Beispiel #11
0
 def get_request(self, deflate=True):
     """
     Returns unsigned AuthnRequest.
     :param deflate: It makes the deflate process optional
     :type: bool
     :return: AuthnRequest maybe deflated and base64 encoded
     :rtype: str object
     """
     if deflate:
         request = OneLogin_Saml2_Utils.deflate_and_base64_encode(self.__authn_request)
     else:
         request = OneLogin_Saml2_Utils.b64encode(self.__authn_request)
     return request
Beispiel #12
0
 def get_response(self, deflate=True):
     """
     Returns a Logout Response object.
     :param deflate: It makes the deflate process optional
     :type: bool
     :return: Logout Response maybe deflated and base64 encoded
     :rtype: string
     """
     if deflate:
         response = OneLogin_Saml2_Utils.deflate_and_base64_encode(self.__logout_response)
     else:
         response = OneLogin_Saml2_Utils.b64encode(self.__logout_response)
     return response
Beispiel #13
0
 def get_request(self, deflate=True):
     """
     Returns the Logout Request deflated, base64encoded
     :param deflate: It makes the deflate process optional
     :type: bool
     :return: Logout Request maybe deflated and base64 encoded
     :rtype: str object
     """
     if deflate:
         request = OneLogin_Saml2_Utils.deflate_and_base64_encode(self.__logout_request)
     else:
         request = OneLogin_Saml2_Utils.b64encode(self.__logout_request)
     return request
 def get_response(self, deflate=True):
     """
     Returns a Logout Response object.
     :param deflate: It makes the deflate process optional
     :type: bool
     :return: Logout Response maybe deflated and base64 encoded
     :rtype: string
     """
     if deflate:
         response = OneLogin_Saml2_Utils.deflate_and_base64_encode(self.__logout_response)
     else:
         response = OneLogin_Saml2_Utils.b64encode(self.__logout_response)
     return response
    def testIsInvalidIssuer(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        Case Invalid Issuer
        """
        request = self.file_contents(join(self.data_path, 'logout_requests', 'invalids', 'invalid_issuer.xml'))
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html'
        }
        current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data)
        request = request.replace('http://stuff.com/endpoints/endpoints/sls.php', current_url)
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
        logout_request = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        try:
            logout_request2 = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
            valid = logout_request2.is_valid(request_data)
            self.assertFalse(valid)
        except Exception as e:
            self.assertIn('Invalid issuer in the Logout Request', str(e))
    def testIsValidRaisesExceptionWhenRaisesArgumentIsTrue(self):
        request = OneLogin_Saml2_Utils.b64encode('<xml>invalid</xml>')
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html',
        }
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
        settings.set_strict(True)

        logout_request = OneLogin_Saml2_Logout_Request(settings, request)

        self.assertFalse(logout_request.is_valid(request_data))

        with self.assertRaises(Exception):
            logout_request.is_valid(request_data, raise_exceptions=True)
Beispiel #17
0
    def testGetXML(self):
        """
        Tests that we can get the logout request XML directly without
        going through intermediate steps
        """
        request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml'))
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())

        logout_request_generated = OneLogin_Saml2_Logout_Request(settings)
        expectedFragment = (
            'Destination="http://idp.example.com/SingleLogoutService.php">\n'
            '    <saml:Issuer>http://stuff.com/endpoints/metadata.php</saml:Issuer>\n'
            '    <saml:NameID SPNameQualifier="http://stuff.com/endpoints/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://idp.example.com/</saml:NameID>\n'
            '    \n</samlp:LogoutRequest>'
        )
        self.assertIn(expectedFragment, logout_request_generated.get_xml())

        logout_request_processed = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request))
        self.assertEqual(request, logout_request_processed.get_xml())
    def testIsInvalidXML(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        Case Invalid XML
        """
        request = OneLogin_Saml2_Utils.b64encode('<xml>invalid</xml>')
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html',
        }
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())

        logout_request = OneLogin_Saml2_Logout_Request(settings, request)

        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        logout_request2 = OneLogin_Saml2_Logout_Request(settings, request)
        self.assertFalse(logout_request2.is_valid(request_data))
    def testIsInvalidXML(self):
        """
        Tests the is_valid method of the OneLogin_Saml2_LogoutRequest
        Case Invalid XML
        """
        request = OneLogin_Saml2_Utils.b64encode('<xml>invalid</xml>')
        request_data = {
            'http_host': 'example.com',
            'script_name': 'index.html',
        }
        settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())

        logout_request = OneLogin_Saml2_Logout_Request(settings, request)

        self.assertTrue(logout_request.is_valid(request_data))

        settings.set_strict(True)
        logout_request2 = OneLogin_Saml2_Logout_Request(settings, request)
        self.assertFalse(logout_request2.is_valid(request_data))
Beispiel #20
0
    def __build_signature(self,
                          data,
                          saml_type,
                          sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
        """
        Builds the Signature
        :param data: The Request data
        :type data: dict

        :param saml_type: The target URL the user should be redirected to
        :type saml_type: string  SAMLRequest | SAMLResponse

        :param sign_algorithm: Signature algorithm method
        :type sign_algorithm: string
        """
        assert saml_type in ('SAMLRequest', 'SAMLResponse')
        key = self.get_settings().get_sp_key()

        if not key:
            raise OneLogin_Saml2_Error(
                "Trying to sign the %s but can't load the SP private key." %
                saml_type, OneLogin_Saml2_Error.PRIVATE_KEY_NOT_FOUND)

        msg = self.__build_sign_query(data[saml_type],
                                      data.get('RelayState', None),
                                      sign_algorithm, saml_type)

        sign_algorithm_transform_map = {
            OneLogin_Saml2_Constants.DSA_SHA1: xmlsec.Transform.DSA_SHA1,
            OneLogin_Saml2_Constants.RSA_SHA1: xmlsec.Transform.RSA_SHA1,
            OneLogin_Saml2_Constants.RSA_SHA256: xmlsec.Transform.RSA_SHA256,
            OneLogin_Saml2_Constants.RSA_SHA384: xmlsec.Transform.RSA_SHA384,
            OneLogin_Saml2_Constants.RSA_SHA512: xmlsec.Transform.RSA_SHA512
        }
        sign_algorithm_transform = sign_algorithm_transform_map.get(
            sign_algorithm, xmlsec.Transform.RSA_SHA1)

        signature = OneLogin_Saml2_Utils.sign_binary(
            msg, key, sign_algorithm_transform,
            self.__settings.is_debug_active())
        data['Signature'] = OneLogin_Saml2_Utils.b64encode(signature)
        data['SigAlg'] = sign_algorithm
Beispiel #21
0
    def __build_signature(self, data, saml_type, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
        """
        Builds the Signature
        :param data: The Request data
        :type data: dict

        :param saml_type: The target URL the user should be redirected to
        :type saml_type: string  SAMLRequest | SAMLResponse

        :param sign_algorithm: Signature algorithm method
        :type sign_algorithm: string
        """
        assert saml_type in ('SAMLRequest', 'SAMLResponse')
        key = self.get_settings().get_sp_key()

        if not key:
            raise OneLogin_Saml2_Error(
                "Trying to sign the %s but can't load the SP private key." % saml_type,
                OneLogin_Saml2_Error.SP_CERTS_NOT_FOUND
            )

        msg = self.__build_sign_query(data[saml_type],
                                      data.get('RelayState', None),
                                      sign_algorithm,
                                      saml_type)

        sign_algorithm_transform_map = {
            OneLogin_Saml2_Constants.DSA_SHA1: xmlsec.Transform.DSA_SHA1,
            OneLogin_Saml2_Constants.RSA_SHA1: xmlsec.Transform.RSA_SHA1,
            OneLogin_Saml2_Constants.RSA_SHA256: xmlsec.Transform.RSA_SHA256,
            OneLogin_Saml2_Constants.RSA_SHA384: xmlsec.Transform.RSA_SHA384,
            OneLogin_Saml2_Constants.RSA_SHA512: xmlsec.Transform.RSA_SHA512
        }
        sign_algorithm_transform = sign_algorithm_transform_map.get(sign_algorithm, xmlsec.Transform.RSA_SHA1)

        signature = OneLogin_Saml2_Utils.sign_binary(msg, key, sign_algorithm_transform, self.__settings.is_debug_active())
        data['Signature'] = OneLogin_Saml2_Utils.b64encode(signature)
        data['SigAlg'] = sign_algorithm
Beispiel #22
0
    def formatError(self, response_obj, srelay, url):
        try:

            # build response fprm
            try:
                with open(
                        os.path.join(globalsObj.modules_basedir,
                                     globalsObj.easyspid_responseFormPath),
                        'rb') as myfile:
                    response_form = myfile.read().decode("utf-8")
            except:
                with open(globalsObj.easyspid_responseFormPath,
                          'rb') as myfile:
                    response_form = myfile.read().decode("utf-8")

            new_response_obj = ResponseObj(httpcode=200, ID=response_obj.id)
            new_response_obj.setError('200')
            new_response_obj.result = response_obj.result

            response_form = response_form.replace("%URLTARGET%", url)
            response_form = response_form.replace("%RELAYSTATE%", srelay)
            response_form = response_form.replace(
                "%RESPONSE%",
                OneLogin_Saml2_Utils.b64encode(response_obj.jsonWrite()))
            self.postTo = response_form

            return new_response_obj

        except Exception as inst:
            response_obj = ResponseObj(httpcode=500)
            response_obj.setError('500')
            logging.getLogger(
                type(self).__module__ + "." + type(self).__qualname__).error(
                    'Exception', exc_info=True)

            return new_response_obj
Beispiel #23
0
    def processResponse(self, chkTime=True, checkInResponseTo=True):

        try:
            # get response and Relay state
            responsePost = self.get_argument('SAMLResponse')
            srelayPost = self.get_argument('RelayState')

            # decode saml response
            #response = responsePost
            self.response = responsePost
            try:
                self.response = OneLogin_Saml2_Utils.decode_base64_and_inflate(
                    responsePost)
            except Exception:
                try:
                    self.response = OneLogin_Saml2_Utils.b64decode(
                        responsePost)
                except Exception:
                    pass

            # try:
            #     #response = OneLogin_Saml2_Utils.b64decode(responsePost)
            #     self.response = OneLogin_Saml2_Utils.b64decode(responsePost)
            # except Exception:
            #     pass

            ## parse XML and make some check
            ns = {
                'md0': OneLogin_Saml2_Constants.NS_SAMLP,
                'md1': OneLogin_Saml2_Constants.NS_SAML
            }
            parsedResponse = xml.etree.ElementTree.fromstring(self.response)

            self.inResponseTo = parsedResponse.get('InResponseTo')
            self.ResponseID = parsedResponse.get('ID')
            issuer = self.issuer = parsedResponse.find("md1:Issuer", ns)
            if issuer is None:
                response_obj = ResponseObj(httpcode=401)
                response_obj.setError('easyspid118')
                return response_obj

            #spByInResponseTo = None
            # try to get sp searching a corresponding request and raise error if checkInResponseTo is True
            # inResponseChk = waitFuture(asyncio.run_coroutine_threadsafe(self.dbobjSaml.execute_statment("chk_idAssertion('%s')" %
            #             inResponseTo), globalsObj.ioloop))
            # if inResponseChk['error'] == 0 and inResponseChk['result'] is not None:
            #         spByInResponseTo = inResponseChk['result'][0]['cod_sp']
            #
            # elif checkInResponseTo and inResponseChk['error'] == 0 and inResponseChk['result'] == None:
            #     response_obj = ResponseObj(httpcode=404, ID = ResponseID)
            #     response_obj.setError('easyspid120')
            #     response_obj.setResult(response = str(response, 'utf-8'))
            #     return response_obj
            #
            # elif inResponseChk['error'] > 0:
            #     response_obj = ResponseObj(httpcode=500)
            #     response_obj.setError('easyspid105')
            #     response_obj.setResult(inResponseChk['result'])
            #     return response_obj

            # try to get sp searching a corresponding request and raise error if checkInResponseTo is True
            spByInResponseTo = self.chkExistsReq(checkInResponseTo)

            ### check StatusCode to find errors
            firstChk = easyspid.lib.utils.validateAssertion(
                str(self.response, 'utf-8'), None, None)
            if not firstChk['chkStatus']:
                #get errors codes
                samlErrors = waitFuture(
                    asyncio.run_coroutine_threadsafe(
                        getResponseError(parsedResponse,
                                         sp=spByInResponseTo,
                                         namespace=ns), globalsObj.ioloop))

                if samlErrors['error'] == '0':
                    response_obj = ResponseObj(httpcode=400,
                                               ID=self.ResponseID)
                    response_obj.setError('easyspid121')
                    response_obj.setResult(response=str(
                        self.response, 'utf-8'),
                                           format='json',
                                           samlErrors=samlErrors['status'])

                    return self.formatError(response_obj, srelayPost,
                                            samlErrors['service'])

                elif samlErrors['error'] == 'easyspid114':
                    response_obj = ResponseObj(httpcode=404)
                    response_obj.setError('easyspid114')
                    return response_obj

                else:
                    response_obj = ResponseObj(httpcode=500)
                    response_obj.setError('500')
                    response_obj.setResult(samlErrors['error'])
                    return response_obj

            #decode Relay state
            #srelay = srelayPost
            self.srelay = srelayPost
            try:
                self.srelay = OneLogin_Saml2_Utils.decode_base64_and_inflate(
                    srelayPost)
            except Exception:
                try:
                    self.srelay = OneLogin_Saml2_Utils.b64decode(srelayPost)

                except Exception:
                    pass

                #self.srelay = OneLogin_Saml2_Utils.b64decode(srelayPost)
                #pass
            # try:
            #      #srelay = OneLogin_Saml2_Utils.b64decode(srelayPost)
            #      self.srelay = OneLogin_Saml2_Utils.b64decode(srelayPost)
            # except Exception:
            #      pass

            ## get sp by ID
            #ns = {'md0': OneLogin_Saml2_Constants.NS_SAMLP, 'md1': OneLogin_Saml2_Constants.NS_SAML}
            #parsedResponse = xml.etree.ElementTree.fromstring(response)
            #issuer = self.issuer = parsedResponse.find("md1:Issuer", ns)
            #inResponseTo = parsedResponse.get('InResponseTo')

            #get audience
            audience = self.audience = parsedResponse.find(
                'md1:Assertion/md1:Conditions/md1:AudienceRestriction/md1:Audience',
                ns)
            if audience is None:
                response_obj = ResponseObj(httpcode=401)
                response_obj.setError('easyspid118')
                return response_obj

            # if issuer is None or audience is None:
            #     response_obj = ResponseObj(httpcode=401)
            #     response_obj.setError('easyspid118')
            #     return response_obj

            #task1 = asyncio.run_coroutine_threadsafe(self.dbobjSaml.execute_statment("chk_idAssertion('%s')" %
            #        inResponseTo), globalsObj.ioloop)
            # task2 = asyncio.run_coroutine_threadsafe(self.dbobjSaml.execute_statment("get_provider_byentityid(%s, '%s')" %
            #         ('True', '{'+(self.issuer.text.strip())+'}')),  globalsObj.ioloop)
            #task3 = asyncio.run_coroutine_threadsafe(self.dbobjSaml.execute_statment("get_provider_byentityid(%s, '%s')" %
            #       ('True', '{'+(audience.text.strip())+'}')),  globalsObj.ioloop)

            #assert not task1.done()
            #inResponseChk = task1.result()
            #inResponseChk = waitFuture(task1)
            #audienceChk = waitFuture(task3)
            #spByAudience = None
            #spByInResponseTo = None

            #if inResponseChk['error'] == 0 and inResponseChk['result'] is not None:
            #    spByInResponseTo = inResponseChk['result'][0]['cod_sp']

            # if audienceChk['error'] == 0 and audienceChk['result'] is not None:
            #     spByAudience = audienceChk['result'][0]['cod_provider']

            #check audinece
            # if spByAudience is None:
            #     response_obj = ResponseObj(httpcode=404)
            #     response_obj.setError('easyspid115')
            #     return response_obj

            # get sp by audience
            spByAudience = self.getSpByAudience()

            #check inresponseTo and spByAudience == spByInResponseTo
            if checkInResponseTo and spByAudience == spByInResponseTo:
                sp = spByAudience

            elif checkInResponseTo and spByAudience != spByInResponseTo:
                response_obj = ResponseObj(httpcode=401)
                response_obj.setError('easyspid110')
                return response_obj

            sp = spByAudience

            # get service by sp and relay_state
            try:
                task = asyncio.run_coroutine_threadsafe(
                    self.dbobjSaml.execute_statment(
                        "get_service(%s, '%s', '%s')" %
                        ('True', str(self.srelay), sp)), globalsObj.ioloop)
                #assert not task.done()
                #service = task.result()
                service = waitFuture(task)

                if service['error'] == 0 and service['result'] is not None:
                    # costruisci il routing
                    self.routing = dict()
                    self.routing['url'] = service['result'][0]['url']
                    self.routing['relaystate'] = self.srelay
                    self.routing['format'] = service['result'][0]['format']

                elif service['error'] > 0 or service['result'] is None:
                    response_obj = ResponseObj(httpcode=500,
                                               debugMessage=service['result'])
                    response_obj.setError("easyspid111")
                    return response_obj

            except Exception:
                pass

            # get IdP
            # idpEntityId = waitFuture(task2)
            #
            # if idpEntityId['error'] == 0 and idpEntityId['result'] is not None:
            #     idp_metadata = idpEntityId['result'][0]['xml']
            #     idp = idpEntityId['result'][0]['cod_provider']
            #
            # elif idpEntityId['error'] == 0 and idpEntityId['result'] is None:
            #     response_obj = ResponseObj(httpcode=404)
            #     response_obj.setError('easyspid103')
            #     return response_obj
            #
            # elif idpEntityId['error'] > 0:
            #     response_obj = ResponseObj(httpcode=500, debugMessage=idpEntityId['result'])
            #     response_obj.setError("easyspid105")
            #     return response_obj

            # get IdP and metadata
            (idp_metadata, idp) = self.getIdentyIdp()

            # get sp settings
            task = asyncio.run_coroutine_threadsafe(
                easyspid.lib.easyspid.spSettings(sp, idp, close=True),
                globalsObj.ioloop)
            sp_settings = waitFuture(task)

            if sp_settings['error'] == 0 and sp_settings['result'] != None:

                ## insert response into DB
                task = asyncio.run_coroutine_threadsafe(
                    self.dbobjSaml.execute_statment(
                        "write_assertion('%s', '%s', '%s', '%s')" %
                        (str(self.response, 'utf-8').replace(
                            "'", "''"), sp, idp, self.remote_ip)),
                    globalsObj.ioloop)
                wrtAuthn = waitFuture(task)

                if wrtAuthn['error'] == 0:

                    if self.routing['format'] == 'saml':
                        return self.passthrough()

                    task = asyncio.run_coroutine_threadsafe(
                        self.dbobjJwt.execute_statment(
                            "get_token_by_cod('%s')" %
                            (wrtAuthn['result'][0]['cod_token'])),
                        globalsObj.ioloop)
                    #assert not task.done()
                    #jwt = task.result()
                    jwt = waitFuture(task)

                else:
                    response_obj = ResponseObj(httpcode=500,
                                               debugMessage=wrtAuthn['result'])
                    response_obj.setError("easyspid105")
                    logging.getLogger(
                        type(self).__module__ + "." +
                        type(self).__qualname__).error('Exception',
                                                       exc_info=True)
                    return response_obj

                # create settings OneLogin dict
                #settings = sp_settings['result']
                prvdSettings = Saml2_Settings(sp_settings['result'])

                chk = easyspid.lib.utils.validateAssertion(
                    str(self.response, 'utf-8'),
                    sp_settings['result']['idp']['x509cert_fingerprint'],
                    sp_settings['result']['idp']['x509cert_fingerprintalg'])

                chk['issuer'] = issuer.text.strip()
                chk['audience'] = audience.text.strip()

                if not chk['chkStatus']:
                    response_obj = ResponseObj(httpcode=401)
                    response_obj.setError('easyspid107')
                    return response_obj

                elif not chk['schemaValidate']:
                    response_obj = ResponseObj(httpcode=401)
                    response_obj.setError('easyspid104')
                    response_obj.setResult(responseValidate=chk)
                    return response_obj

                elif not chk['signCheck']:
                    response_obj = ResponseObj(httpcode=401)
                    response_obj.setError('easyspid106')
                    response_obj.setResult(responseValidate=chk)
                    return response_obj

                elif not chk[
                        'certAllowed'] and globalsObj.easyspid_checkCertificateAllowed:
                    response_obj = ResponseObj(httpcode=401)
                    response_obj.setError('easyspid116')
                    response_obj.setResult(responseValidate=chk)
                    return response_obj

                elif not chk[
                        'certValidity'] and globalsObj.easyspid_checkCertificateValidity:
                    response_obj = ResponseObj(httpcode=401)
                    response_obj.setError('easyspid117')
                    response_obj.setResult(responseValidate=chk)
                    return response_obj

                elif chkTime and not chk['chkTime']:
                    response_obj = ResponseObj(httpcode=401)
                    response_obj.setError('easyspid108')
                    return response_obj

                #get all attributes
                attributes = chk['serviceAttributes']
                attributes_tmp = dict()
                for key in attributes:
                    attributes_tmp[key] = attributes[key][0]
                attributes = attributes_tmp

                # build response form
                try:
                    with open(
                            os.path.join(globalsObj.modules_basedir,
                                         globalsObj.easyspid_responseFormPath),
                            'rb') as myfile:
                        response_form = myfile.read().decode("utf-8")
                except:
                    with open(globalsObj.easyspid_responseFormPath,
                              'rb') as myfile:
                        response_form = myfile.read().decode("utf-8")

                response_obj = ResponseObj(
                    httpcode=200, ID=wrtAuthn['result'][0]['ID_assertion'])
                response_obj.setError('200')
                response_obj.setResult(attributes=attributes,
                                       jwt=jwt['result'][0]['token'],
                                       responseValidate=chk,
                                       response=str(self.response, 'utf-8'),
                                       format='json')

                response_form = response_form.replace("%URLTARGET%",
                                                      self.routing['url'])
                response_form = response_form.replace("%RELAYSTATE%",
                                                      srelayPost)
                response_form = response_form.replace(
                    "%RESPONSE%",
                    OneLogin_Saml2_Utils.b64encode(response_obj.jsonWrite()))
                self.postTo = response_form

            elif sp_settings['error'] == 0 and sp_settings['result'] == None:
                response_obj = ResponseObj(httpcode=404)
                response_obj.setError('easyspid114')

            elif sp_settings['error'] > 0:
                #response_obj = sp_settings['result']
                response_obj = sp_settings

        except goExit as e:
            return e.expression

        except tornado.web.MissingArgumentError as error:
            response_obj = ResponseObj(debugMessage=error.log_message,
                                       httpcode=error.status_code,
                                       devMessage=error.log_message)
            response_obj.setError(str(error.status_code))
            logging.getLogger(
                type(self).__module__ + "." + type(self).__qualname__).error(
                    '%s' % error, exc_info=True)

        except Exception as inst:
            response_obj = ResponseObj(httpcode=500)
            response_obj.setError('500')
            logging.getLogger(
                type(self).__module__ + "." + type(self).__qualname__).error(
                    'Exception', exc_info=True)

        return response_obj
Beispiel #24
0
    def loginAuthnReq(self, sp_settings, idp_metadata, attributeIndex, binding,
                      srelay_cod):
        try:

            if binding == 'redirect':
                authn_request = authnreqBuildhandler.buildAthnReq(
                    self, sp_settings, attributeIndex, signed=False)
            elif binding == 'post':
                authn_request = authnreqBuildhandler.buildAthnReq(
                    self, sp_settings, attributeIndex, signed=True)

            bindingMap = {
                'redirect': OneLogin_Saml2_Constants.BINDING_HTTP_REDIRECT,
                'post': OneLogin_Saml2_Constants.BINDING_HTTP_POST
            }

            if (sp_settings['error'] == 0 and sp_settings['result'] is not None
                    and idp_metadata.error.code == '200'
                    and authn_request.error.code == '200'):

                sp = sp_settings['result']['sp']['cod_sp']
                idp = sp_settings['result']['idp']['cod_idp']

                # get relay state
                task = asyncio.run_coroutine_threadsafe(
                    self.dbobjSaml.execute_statment(
                        "get_service(%s, '%s', '%s')" %
                        ('True', str(srelay_cod), sp)), globalsObj.ioloop)
                #assert not task.done()
                #srelay = task.result()
                srelay = waitFuture(task)

                if srelay['error'] == 0 and srelay['result'] is None:
                    response_obj = ResponseObj(httpcode=404)
                    response_obj.setError('easyspid113')
                    return response_obj

                elif srelay['error'] > 0:
                    response_obj = ResponseObj(
                        httpcode=500, debugMessage=sp_settings['result'])
                    response_obj.setError("easyspid105")
                    return response_obj

            #if (sp_settings['error'] == 0 and sp_settings['result'] is not None
            #and idp_metadata.error.code == '200' and authn_request.error.code == '200'):

                idp_data = OneLogin_Saml2_IdPMetadataParser.parse(
                    idp_metadata.result.metadata,
                    required_sso_binding=bindingMap[binding],
                    required_slo_binding=bindingMap[binding])
                idp_settings = idp_data['idp']

                # fake authn_request
                req = {
                    "http_host": "",
                    "script_name": "",
                    "server_port": "",
                    "get_data": "",
                    "post_data": ""
                }

                settings = sp_settings['result']
                if 'entityId' in idp_settings:
                    settings['idp']['entityId'] = idp_settings['entityId']
                if 'singleLogoutService' in idp_settings:
                    settings['idp']['singleLogoutService'] = idp_settings[
                        'singleLogoutService']
                if 'singleSignOnService' in idp_settings:
                    settings['idp']['singleSignOnService'] = idp_settings[
                        'singleSignOnService']
                if 'x509cert' in idp_settings:
                    settings['idp']['x509cert'] = idp_settings['x509cert']

                auth = OneLogin_Saml2_Auth(req, sp_settings['result'])
                spSettings = Saml2_Settings(sp_settings['result'])

                sign_alg = (
                    spSettings.get_security_data())['signatureAlgorithm']

                # build login message
                # redirect binding
                if binding == 'redirect':
                    saml_request = OneLogin_Saml2_Utils.deflate_and_base64_encode(
                        authn_request.result.authnrequest)
                    parameters = {'SAMLRequest': saml_request}
                    parameters['RelayState'] = srelay['result'][0][
                        'relay_state']
                    auth.add_request_signature(parameters, sign_alg)
                    redirectLocation = auth.redirect_to(
                        auth.get_sso_url(), parameters)

                    response_obj = ResponseObj(httpcode=200)
                    response_obj.setError('200')
                    response_obj.setResult(redirectTo=redirectLocation,
                                           jwt=authn_request.result.jwt)

                # POST binding
                elif binding == 'post':
                    saml_request_signed = OneLogin_Saml2_Utils.b64encode(
                        authn_request.result.authnrequest)
                    relay_state = OneLogin_Saml2_Utils.b64encode(
                        srelay['result'][0]['relay_state'])
                    idpsso = idp_settings['singleSignOnService']['url']

                    try:
                        with open(
                                os.path.join(globalsObj.modules_basedir,
                                             globalsObj.easyspid_postFormPath),
                                'rb') as myfile:
                            post_form = myfile.read().decode("utf-8").replace(
                                '\n', '')
                    except:
                        with open(globalsObj.easyspid_postFormPath,
                                  'rb') as myfile:
                            post_form = myfile.read().decode("utf-8").replace(
                                '\n', '')

                    post_form = post_form.replace("%IDPSSO%", idpsso)
                    post_form = post_form.replace("%AUTHNREQUEST%",
                                                  saml_request_signed)
                    post_form = post_form.replace("%RELAYSTATE%", relay_state)

                    response_obj = ResponseObj(httpcode=200)
                    response_obj.setError('200')
                    response_obj.setResult(postTo=post_form,
                                           jwt=authn_request.result.jwt)

            elif sp_settings['error'] == 0 and sp_settings['result'] is None:
                response_obj = ResponseObj(httpcode=404)
                response_obj.setError('easyspid101')

            elif sp_settings['error'] > 0:
                response_obj = ResponseObj(httpcode=500,
                                           debugMessage=sp_settings['result'])
                response_obj.setError("easyspid105")

        except tornado.web.MissingArgumentError as error:
            response_obj = ResponseObj(debugMessage=error.log_message,
                                       httpcode=error.status_code,
                                       devMessage=error.log_message)
            response_obj.setError(str(error.status_code))
            logging.getLogger(
                type(self).__module__ + "." + type(self).__qualname__).error(
                    '%s' % error, exc_info=True)

        except Exception as inst:
            response_obj = ResponseObj(httpcode=500)
            response_obj.setError('500')
            logging.getLogger(
                type(self).__module__ + "." + type(self).__qualname__).error(
                    'Exception', exc_info=True)

        return response_obj
Beispiel #25
0
    def test_full_login_process(self):
        """Asserts the nominal login process works."""
        sso_location = "http://testserver/account/saml/local-accepting-idp/sso/"
        entity_descriptor_list = [
            generate_idp_metadata(
                entity_id=sso_location,
                sso_location=sso_location,
                ui_info_display_names=format_mdui_display_name(
                    "Local accepting IdP"),
            ),
        ]

        # 1/ Select Idp in the provider list
        with mock.patch("urllib.request.urlopen") as urlopen_mock:

            class UrlOpenMock:
                """Mockin object for the urlopen"""
                def read(self):
                    """Allow object to be read several times."""
                    return generate_idp_federation_metadata(
                        entity_descriptor_list=entity_descriptor_list,
                    ).encode("utf-8")

            urlopen_mock.return_value = UrlOpenMock()

            response = self.client.get(
                reverse("account:saml_fer_idp_choice"), )

            self.assertContains(
                response,
                f'action="{reverse("account:social:begin", args=("saml_fer",))}"',
            )
            self.assertContains(response, "local-accepting-idp")

            response = self.client.get(
                f'{reverse("account:social:begin", args=("saml_fer",))}?idp=local-accepting-idp',
            )

            self.assertEqual(response.status_code, 302)
            self.assertTrue(response["Location"].startswith(
                "http://testserver/account/saml/local-accepting-idp/sso/?SAMLRequest="
            ))

            # 2/ Fake the redirection to the SSO
            response = self.client.get(
                f'{reverse("account:social:begin", args=("saml_fer",))}?idp=local-accepting-idp',
                follow=False,
            )

            # 3/ Generate SAML response using SAML request
            query_values = parse_qs(urlparse(response["Location"]).query)
            saml_request = query_values["SAMLRequest"]
            saml_relay_state = query_values["RelayState"]
            readable_saml_request = OneLogin_Saml2_Utils.decode_base64_and_inflate(
                saml_request, )
            saml_request = OneLogin_Saml2_XML.to_etree(readable_saml_request)
            saml_acs_url = saml_request.get("AssertionConsumerServiceURL")
            request_id = saml_request.get("ID")

            auth_response = OneLogin_Saml2_Utils.b64encode(
                generate_auth_response(
                    request_id,
                    saml_acs_url,
                    issuer=
                    "http://testserver/account/saml/local-accepting-idp/sso/",
                ))

            # 4/ POST the data to our endpoint
            response = self.client.post(
                saml_acs_url,
                data={
                    "RelayState": saml_relay_state,
                    "SAMLResponse": auth_response,
                },
            )
            self.assertEqual(response.status_code, 302)
            self.assertEqual(response["Location"], "/")

        # Assert the user is authenticated
        user = auth_get_user(self.client)
        self.assertTrue(user.is_authenticated)

        # Assert the user has an organization
        organization_access = user.organization_accesses.select_related(
            "organization").get()  # also assert there is only one organization
        self.assertEqual(organization_access.role, STUDENT)
        self.assertEqual(organization_access.organization.name,
                         "OrganizationDName")