def test_generate_payload_no_query_string(self):
        vp = ValidationPayload(
            method='GET',
            path='https://api.twilio.com/',
            query_string='',
            signed_headers=['headerb', 'headera'],
            all_headers={'head': 'toe', 'Headerb': 'valb', 'yeezy': 'weezy'},
            body='me=letop&you=leworst'
        )

        expected_payload = '\n'.join([
            'GET',
            'https://api.twilio.com/',
            '',
            'headerb:valb',
            '',
            'headera;headerb',
            '{}'.format(ClientValidationJwt._hash('me=letop&you=leworst'))
        ])
        expected_payload = ClientValidationJwt._hash(expected_payload)

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        actual_payload = jwt._generate_payload()
        self.assertEqual('headera;headerb', actual_payload['hrh'])
        self.assertEqual(expected_payload, actual_payload['rqh'])
    def test_generate_payload_no_req_body(self):
        vp = ValidationPayload(
            method='GET',
            path='https://api.twilio.com/',
            query_string='q1=v1',
            signed_headers=['headerb', 'headera'],
            all_headers={'head': 'toe', 'headera': 'vala', 'headerb': 'valb'},
            body=''
        )

        expected_payload = '\n'.join([
            'GET',
            'https://api.twilio.com/',
            'q1=v1',
            'headera:vala',
            'headerb:valb',
            '',
            'headera;headerb',
            ''
        ])
        expected_payload = ClientValidationJwt._hash(expected_payload)

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        actual_payload = jwt._generate_payload()
        self.assertEqual('headera;headerb', actual_payload['hrh'])
        self.assertEqual(expected_payload, actual_payload['rqh'])
예제 #3
0
    def request(self,
                method,
                url,
                params=None,
                data=None,
                headers=None,
                auth=None,
                timeout=None,
                allow_redirects=False):
        """
        Make a signed HTTP Request

        :param str method: The HTTP method to use
        :param str url: The URL to request
        :param dict params: Query parameters to append to the URL
        :param dict data: Parameters to go in the body of the HTTP request
        :param dict headers: HTTP Headers to send with the request
        :param tuple auth: Basic Auth arguments
        :param float timeout: Socket/Read timeout for the request
        :param boolean allow_redirects: Whether or not to allow redirects
        See the requests documentation for explanation of all these parameters

        :return: An http response
        :rtype: A :class:`Response <twilio.rest.http.response.Response>` object
        """
        session = Session()
        session.verify = get_cert_file()

        request = Request(method.upper(),
                          url,
                          params=params,
                          data=data,
                          headers=headers,
                          auth=auth)
        prepared_request = session.prepare_request(request)

        if 'Host' not in prepared_request.headers and 'host' not in prepared_request.headers:
            prepared_request.headers['Host'] = self._get_host(prepared_request)

        validation_payload = self._build_validation_payload(prepared_request)
        jwt = ClientValidationJwt(self.account_sid, self.api_key_sid,
                                  self.credential_sid, self.private_key,
                                  validation_payload)
        prepared_request.headers['Twilio-Client-Validation'] = jwt.to_jwt()

        response = session.send(
            prepared_request,
            allow_redirects=allow_redirects,
            timeout=timeout,
        )

        return Response(int(response.status_code),
                        response.content.decode('utf-8'))
예제 #4
0
    def test_jwt_payload(self):
        vp = ValidationPayload(method='GET',
                               path='/Messages',
                               query_string='PageSize=5&Limit=10',
                               signed_headers=['authorization', 'host'],
                               all_headers={
                                   'authorization': 'foobar',
                                   'host': 'api.twilio.com'
                               },
                               body='foobar')
        expected_hash = '4dc9b67bed579647914587b0e22a1c65c1641d8674797cd82de65e766cce5f80'

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        self.assertDictContainsSubset(
            {
                'hrh': 'authorization;host',
                'rqh': expected_hash,
                'iss': 'SK123',
                'sub': 'AC123',
            }, jwt.payload)
        self.assertGreaterEqual(jwt.payload['exp'], time.time(),
                                'JWT exp is before now')
        self.assertLessEqual(jwt.payload['exp'],
                             time.time() + 301, 'JWT exp is after now + 5mins')
        self.assertDictEqual(
            {
                'alg': 'RS256',
                'typ': 'JWT',
                'cty': 'twilio-pkrv;v=1',
                'kid': 'CR123'
            }, jwt.headers)
    def test_generate_payload_schema_correct_2(self):
        """Test against a known good rqh payload hash"""
        vp = ValidationPayload(
            method='POST',
            path='/Messages',
            query_string='',
            signed_headers=['authorization', 'host'],
            all_headers={'authorization': 'foobar', 'host': 'api.twilio.com'},
            body='testbody'
        )

        expected_hash = 'bd792c967c20d546c738b94068f5f72758a10d26c12979677501e1eefe58c65a'

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        actual_payload = jwt._generate_payload()
        self.assertEqual('authorization;host', actual_payload['hrh'])
        self.assertEqual(expected_hash, actual_payload['rqh'])
    def test_generate_payload_schema_correct_1(self):
        """Test against a known good rqh payload hash"""
        vp = ValidationPayload(
            method='GET',
            path='/Messages',
            query_string='PageSize=5&Limit=10',
            signed_headers=['authorization', 'host'],
            all_headers={'authorization': 'foobar', 'host': 'api.twilio.com'},
            body='foobar'
        )

        expected_hash = '4dc9b67bed579647914587b0e22a1c65c1641d8674797cd82de65e766cce5f80'

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        actual_payload = jwt._generate_payload()
        self.assertEqual('authorization;host', actual_payload['hrh'])
        self.assertEqual(expected_hash, actual_payload['rqh'])
예제 #7
0
    def test_generate_payload_schema_correct_2(self):
        """Test against a known good rqh payload hash"""
        vp = ValidationPayload(method='POST',
                               path='/Messages',
                               query_string='',
                               signed_headers=['authorization', 'host'],
                               all_headers={
                                   'authorization': 'foobar',
                                   'host': 'api.twilio.com'
                               },
                               body='testbody')

        expected_hash = 'bd792c967c20d546c738b94068f5f72758a10d26c12979677501e1eefe58c65a'

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        actual_payload = jwt._generate_payload()
        self.assertEqual('authorization;host', actual_payload['hrh'])
        self.assertEqual(expected_hash, actual_payload['rqh'])
예제 #8
0
    def test_generate_payload_schema_correct_1(self):
        """Test against a known good rqh payload hash"""
        vp = ValidationPayload(method='GET',
                               path='/Messages',
                               query_string='PageSize=5&Limit=10',
                               signed_headers=['authorization', 'host'],
                               all_headers={
                                   'authorization': 'foobar',
                                   'host': 'api.twilio.com'
                               },
                               body='foobar')

        expected_hash = '4dc9b67bed579647914587b0e22a1c65c1641d8674797cd82de65e766cce5f80'

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        actual_payload = jwt._generate_payload()
        self.assertEqual('authorization;host', actual_payload['hrh'])
        self.assertEqual(expected_hash, actual_payload['rqh'])
예제 #9
0
    def test_generate_payload_no_headers(self):
        vp = ValidationPayload(method='GET',
                               path='https://api.twilio.com/',
                               query_string='q1=v1',
                               signed_headers=['headerb', 'headera'],
                               all_headers={},
                               body='me=letop&you=leworst')

        expected_payload = '\n'.join([
            'GET', 'https://api.twilio.com/', 'q1=v1', '', 'headera;headerb',
            '{}'.format(ClientValidationJwt._hash('me=letop&you=leworst'))
        ])
        expected_payload = ClientValidationJwt._hash(expected_payload)

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        actual_payload = jwt._generate_payload()
        self.assertEqual('headera;headerb', actual_payload['hrh'])
        self.assertEqual(expected_payload, actual_payload['rqh'])
예제 #10
0
    def test_jwt_signing(self):
        vp = ValidationPayload(method='GET',
                               path='/Messages',
                               query_string='PageSize=5&Limit=10',
                               signed_headers=['authorization', 'host'],
                               all_headers={
                                   'authorization': 'foobar',
                                   'host': 'api.twilio.com'
                               },
                               body='foobar')
        expected_hash = '4dc9b67bed579647914587b0e22a1c65c1641d8674797cd82de65e766cce5f80'

        private_key = rsa.generate_private_key(public_exponent=65537,
                                               key_size=2048,
                                               backend=default_backend())
        public_key = private_key.public_key().public_bytes(
            Encoding.PEM, PublicFormat.PKCS1)
        private_key = private_key.private_bytes(Encoding.PEM,
                                                PrivateFormat.PKCS8,
                                                NoEncryption())

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', private_key, vp)
        decoded = Jwt.from_jwt(jwt.to_jwt(), public_key)

        self.assertDictContainsSubset(
            {
                'hrh': 'authorization;host',
                'rqh': expected_hash,
                'iss': 'SK123',
                'sub': 'AC123',
            }, decoded.payload)
        self.assertGreaterEqual(decoded.payload['exp'], time.time(),
                                'JWT exp is before now')
        self.assertLessEqual(decoded.payload['exp'],
                             time.time() + 501, 'JWT exp is after now + 5m')
        self.assertDictEqual(
            {
                'alg': 'RS256',
                'typ': 'JWT',
                'cty': 'twilio-pkrv;v=1',
                'kid': 'CR123'
            }, decoded.headers)
예제 #11
0
    def test_generate_payload_no_req_body(self):
        vp = ValidationPayload(method='GET',
                               path='https://api.twilio.com/',
                               query_string='q1=v1',
                               signed_headers=['headerb', 'headera'],
                               all_headers={
                                   'head': 'toe',
                                   'headera': 'vala',
                                   'headerb': 'valb'
                               },
                               body='')

        expected_payload = '\n'.join([
            'GET', 'https://api.twilio.com/', 'q1=v1', 'headera:vala',
            'headerb:valb', '', 'headera;headerb', ''
        ])
        expected_payload = ClientValidationJwt._hash(expected_payload)

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        actual_payload = jwt._generate_payload()
        self.assertEqual('headera;headerb', actual_payload['hrh'])
        self.assertEqual(expected_payload, actual_payload['rqh'])
예제 #12
0
    def request(self, method, url, params=None, data=None, headers=None, auth=None, timeout=None,
                allow_redirects=False):
        """
        Make a signed HTTP Request

        :param str method: The HTTP method to use
        :param str url: The URL to request
        :param dict params: Query parameters to append to the URL
        :param dict data: Parameters to go in the body of the HTTP request
        :param dict headers: HTTP Headers to send with the request
        :param tuple auth: Basic Auth arguments
        :param float timeout: Socket/Read timeout for the request
        :param boolean allow_redirects: Whether or not to allow redirects
        See the requests documentation for explanation of all these parameters

        :return: An http response
        :rtype: A :class:`Response <twilio.rest.http.response.Response>` object
        """
        session = self.session or Session()
        request = Request(method.upper(), url, params=params, data=data, headers=headers, auth=auth)
        prepared_request = session.prepare_request(request)

        if 'Host' not in prepared_request.headers and 'host' not in prepared_request.headers:
            prepared_request.headers['Host'] = self._get_host(prepared_request)

        validation_payload = self._build_validation_payload(prepared_request)
        jwt = ClientValidationJwt(self.account_sid, self.api_key_sid, self.credential_sid,
                                  self.private_key, validation_payload)
        prepared_request.headers['Twilio-Client-Validation'] = jwt.to_jwt()

        response = session.send(
            prepared_request,
            allow_redirects=allow_redirects,
            timeout=timeout,
        )

        return Response(int(response.status_code), response.text)
예제 #13
0
    def test_generate_payload_complex(self):
        vp = ValidationPayload(method='GET',
                               path='https://api.twilio_code.com/',
                               query_string='q1=v1&q2=v2&a=b',
                               signed_headers=['headerb', 'headera'],
                               all_headers={
                                   'head': 'toe',
                                   'Headerb': 'valb',
                                   'yeezy': 'weezy'
                               },
                               body='me=letop&you=leworst')

        expected_payload = '\n'.join([
            'GET', 'https://api.twilio_code.com/', 'a=b&q1=v1&q2=v2',
            'headerb:valb', '', 'headera;headerb',
            '{}'.format(ClientValidationJwt._hash('me=letop&you=leworst'))
        ])
        expected_payload = ClientValidationJwt._hash(expected_payload)

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', 'secret', vp)

        actual_payload = jwt._generate_payload()
        self.assertEqual('headera;headerb', actual_payload['hrh'])
        self.assertEqual(expected_payload, actual_payload['rqh'])
    def test_jwt_signing(self):
        vp = ValidationPayload(
            method='GET',
            path='/Messages',
            query_string='PageSize=5&Limit=10',
            signed_headers=['authorization', 'host'],
            all_headers={'authorization': 'foobar', 'host': 'api.twilio.com'},
            body='foobar'
        )
        expected_hash = '4dc9b67bed579647914587b0e22a1c65c1641d8674797cd82de65e766cce5f80'

        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend()
        )
        public_key = private_key.public_key().public_bytes(Encoding.PEM, PublicFormat.PKCS1)
        private_key = private_key.private_bytes(Encoding.PEM, PrivateFormat.PKCS8, NoEncryption())

        jwt = ClientValidationJwt('AC123', 'SK123', 'CR123', private_key, vp)
        decoded = Jwt.from_jwt(jwt.to_jwt(), public_key)

        self.assertDictContainsSubset({
            'hrh': 'authorization;host',
            'rqh': expected_hash,
            'iss': 'SK123',
            'sub': 'AC123',
        }, decoded.payload)
        self.assertGreaterEqual(decoded.payload['exp'], time.time(), 'JWT exp is before now')
        self.assertLessEqual(decoded.payload['exp'], time.time() + 501, 'JWT exp is after now + 5m')
        self.assertDictEqual({
            'alg': 'RS256',
            'typ': 'JWT',
            'cty': 'twilio-pkrv;v=1',
            'kid': 'CR123'
        }, decoded.headers)