def test_password_digest_custom(monkeypatch): monkeypatch.setattr(os, "urandom", lambda x: b"mocked-random") envelope = load_xml(""" <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """) created = datetime.datetime(2016, 6, 4, 20, 10) token = UsernameToken( "michael", password_digest="12345", use_digest=True, nonce="iets", created=created, ) envelope, headers = token.apply(envelope, {}) expected = """ <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap-env:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>michael</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">12345</wsse:Password> <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">aWV0cw==</wsse:Nonce> <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2016-06-04T20:10:00+00:00</wsu:Created> </wsse:UsernameToken> </wsse:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """ # noqa assert_nodes_equal(envelope, expected)
def test_password_prepared(): envelope = load_xml( """ <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <soap-env:Header xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <ns0:Security> <ns0:UsernameToken/> </ns0:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """ ) # noqa token = UsernameToken("michael", "geheim") envelope, headers = token.apply(envelope, {}) expected = """ <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap-env:Header xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <ns0:Security> <ns0:UsernameToken> <ns0:Username>michael</ns0:Username> <ns0:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">geheim</ns0:Password> </ns0:UsernameToken> </ns0:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """ # noqa assert_nodes_equal(envelope, expected)
def test_password_digest_custom(monkeypatch): monkeypatch.setattr(os, 'urandom', lambda x: b'mocked-random') envelope = load_xml(""" <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """) created = datetime.datetime(2016, 6, 4, 20, 10) token = UsernameToken( 'michael', password_digest='12345', use_digest=True, nonce='iets', created=created) envelope, headers = token.apply(envelope, {}) expected = """ <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap-env:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>michael</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">12345</wsse:Password> <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">aWV0cw==</wsse:Nonce> <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2016-06-04T20:10:00+00:00</wsu:Created> </wsse:UsernameToken> </wsse:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """ # noqa assert_nodes_equal(envelope, expected)
def test_password_digest(monkeypatch): monkeypatch.setattr(os, "urandom", lambda x: b"mocked-random") envelope = load_xml( """ <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """ ) token = UsernameToken("michael", "geheim", use_digest=True) envelope, headers = token.apply(envelope, {}) expected = """ <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap-env:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>michael</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">hVicspAQSg70JNhe67OHqD9gexc=</wsse:Password> <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bW9ja2VkLXJhbmRvbQ==</wsse:Nonce> <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2016-05-08T12:00:00+00:00</wsu:Created> </wsse:UsernameToken> </wsse:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """ # noqa assert_nodes_equal(envelope, expected)
def test_password_prepared(): envelope = load_xml(""" <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <soap-env:Header xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <ns0:Security> <ns0:UsernameToken/> </ns0:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """) # noqa token = UsernameToken('michael', 'geheim') envelope, headers = token.apply(envelope, {}) expected = """ <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap-env:Header xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <ns0:Security> <ns0:UsernameToken> <ns0:Username>michael</ns0:Username> <ns0:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">geheim</ns0:Password> </ns0:UsernameToken> </ns0:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """ # noqa assert_nodes_equal(envelope, expected)
def test_password_digest(monkeypatch): monkeypatch.setattr(os, 'urandom', lambda x: b'mocked-random') envelope = load_xml(""" <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """) token = UsernameToken('michael', 'geheim', use_digest=True) envelope, headers = token.apply(envelope, {}) expected = """ <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap-env:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>michael</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">hVicspAQSg70JNhe67OHqD9gexc=</wsse:Password> <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bW9ja2VkLXJhbmRvbQ==</wsse:Nonce> <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2016-05-08T12:00:00+00:00</wsu:Created> </wsse:UsernameToken> </wsse:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """ # noqa assert_nodes_equal(envelope, expected)
def __init__(self, username, password, wsUrl): passwordHash = hashlib.sha1(password.encode('utf-8')).hexdigest() self._client = zeep.Client( wsUrl, strict=False, wsse=UsernameToken(username, password=passwordHash))
def __init__(self, username, password, baseUrl): passwordHash = hashlib.sha1(password.encode('utf-8')).hexdigest() wsUrl = baseUrl + '/ws/study/v1/studySubjectWsdl.wsdl' self._client = zeep.Client( wsUrl, strict=False, wsse=UsernameToken(username, password=passwordHash))
def __init__(self, username, password): password = hashlib.sha1(password.encode('utf-8')).hexdigest() self._client = zeep.Client( 'https://tds-edc.com/rdpws/ws/study/v1/studyWsdl.wsdl', strict=False, wsse=UsernameToken(username, password=password))
def __init__(self, username, password, baseUrl): self._username = username passwordHash = hashlib.sha1(password.encode('utf-8')).hexdigest() self._passwordHash = hashlib.sha1(password.encode('utf-8')).hexdigest() wsUrl = baseUrl + '/ws/event/v1/eventWsdl.wsdl' self._thisURL = wsUrl self._client = zeep.Client(wsUrl, strict=False, wsse=UsernameToken(username, password=passwordHash))
def get_client(wsdl=None, job_board=None): wsdl = wsdl or settings.TALENTLINK_API_WSDL # Each job_board should define on settings a corresponding API USERNAME # Eg. TALENTLINK_API_USERNAME_INTERNAL api_username = getattr( settings, "TALENTLINK_API_USERNAME_" + job_board.upper() ) # Will throw AttributeError if not defined. return Client( wsdl, transport=ZeepAPIKeyTransport( cache=ZeepDjangoBackendCache(), api_key=settings.TALENTLINK_API_KEY ), wsse=UsernameToken(api_username, settings.TALENTLINK_API_PASSWORD), )
def issue_credit(self, order_number, basket, reference_number, amount, currency): """ Verify the payment processor used for the original order responds as expected to the refund request, and the response is saved in the database, with error handling. """ try: client = Client(self.soap_api_url, wsse=UsernameToken(self.merchant_id, self.transaction_key)) credit_service = { 'captureRequestID': reference_number, 'run': 'true', } purchase_totals = { 'currency': currency, 'grandTotalAmount': str(amount), } response = client.service.runTransaction( merchantID=self.merchant_id, merchantReferenceCode=order_number, orderRequestToken=reference_number, ccCreditService=credit_service, purchaseTotals=purchase_totals) request_id = response.requestID ppr = self.record_processor_response(serialize_object(response), transaction_id=request_id, basket=basket) except: msg = 'An error occurred while attempting to issue a credit (via CyberSource) for order [{}].'.format( order_number) logger.exception(msg) raise GatewayError(msg) if response.decision == 'ACCEPT': return request_id raise GatewayError( 'Failed to issue CyberSource credit for order [{order_number}]. ' 'Complete response has been recorded in entry [{response_id}]'. format(order_number=order_number, response_id=ppr.id))
def create_client(wsdl: str, raw_response: bool = True) -> CachingClient: """ Creates Zeep client that caches the WSDL. :param str wsdl: Link to the WSDL :param bool raw_response: Whether the client should return the raw XML response :return CachingClient client: Zeep client """ # We want the raw response as there is an error when Zeep parses the XML settings: Settings = Settings(raw_response=raw_response) # Client that caches the WSDL client: CachingClient = CachingClient( wsdl=wsdl, # TODO: Store PW encrypted wsse=UsernameToken("n00394gz", "g427Ix19LMB"), settings=settings, ) logger.debug(f"Client created") return client
def test_integration(): client_obj = client.Client("tests/wsdl_files/soap.wsdl", wsse=UsernameToken("username", "password")) response = """ <?xml version="1.0"?> <soapenv:Envelope xmlns:soapenv="https://schemas.xmlsoap.org/soap/envelope/" xmlns:stoc="http://example.com/stockquote.xsd"> <soapenv:Header/> <soapenv:Body> <stoc:TradePrice> <price>120.123</price> </stoc:TradePrice> </soapenv:Body> </soapenv:Envelope> """.strip() with requests_mock.mock() as m: m.post("http://example.com/stockquote", text=response) result = client_obj.service.GetLastTradePrice("foobar") assert result == 120.123
def request_apple_pay_authorization(self, basket, billing_address, payment_token): """ Authorizes an Apple Pay payment. For details on the process, see the CyberSource Simple Order API documentation at https://www.cybersource.com/developers/integration_methods/apple_pay/. Args: basket (Basket) billing_address (BillingAddress) payment_token (dict) Returns: HandledProcessorResponse Raises: GatewayError """ try: client = Client(self.soap_api_url, wsse=UsernameToken(self.merchant_id, self.transaction_key)) card_type = APPLE_PAY_CYBERSOURCE_CARD_TYPE_MAP[ payment_token['paymentMethod']['network'].lower()] bill_to = { 'firstName': billing_address.first_name, 'lastName': billing_address.last_name, 'street1': billing_address.line1, 'street2': billing_address.line2, 'city': billing_address.line4, 'state': billing_address.state, 'postalCode': billing_address.postcode, 'country': billing_address.country.iso_3166_1_a2, 'email': basket.owner.email, } purchase_totals = { 'currency': basket.currency, 'grandTotalAmount': str(basket.total_incl_tax), } encrypted_payment = { 'descriptor': 'RklEPUNPTU1PTi5BUFBMRS5JTkFQUC5QQVlNRU5U', 'data': base64.b64encode(json.dumps(payment_token['paymentData'])), 'encoding': 'Base64', } card = { 'cardType': card_type, } auth_service = { 'run': 'true', } capture_service = { 'run': 'true', } # Enable Export Compliance for SDN validation, amongst other checks. # See https://www.cybersource.com/products/fraud_management/export_compliance/ export_service = { 'run': 'true', } item = [{ 'id': index, 'productCode': line.product.get_product_class().slug, 'productName': clean_field_value(line.product.title), 'quantity': line.quantity, 'productSKU': line.stockrecord.partner_sku, 'taxAmount': str(line.line_tax), 'unitPrice': str(line.unit_price_incl_tax), } for index, line in enumerate(basket.all_lines())] response = client.service.runTransaction( merchantID=self.merchant_id, merchantReferenceCode=basket.order_number, billTo=bill_to, purchaseTotals=purchase_totals, encryptedPayment=encrypted_payment, card=card, ccAuthService=auth_service, ccCaptureService=capture_service, exportService=export_service, paymentSolution='001', item=item, ) except: msg = 'An error occurred while authorizing an Apple Pay (via CyberSource) for basket [{}]'.format( basket.id) logger.exception(msg) raise GatewayError(msg) request_id = response.requestID ppr = self.record_processor_response(serialize_object(response), transaction_id=request_id, basket=basket) if response.decision == 'ACCEPT': currency = basket.currency total = basket.total_incl_tax transaction_id = request_id return HandledProcessorResponse( transaction_id=transaction_id, total=total, currency=currency, card_number='Apple Pay', card_type=CYBERSOURCE_CARD_TYPE_MAP.get(card_type)) else: msg = ( 'CyberSource rejected an Apple Pay authorization request for basket [{basket_id}]. ' 'Complete response has been recorded in entry [{response_id}]') msg = msg.format(basket_id=basket.id, response_id=ppr.id) logger.warning(msg) raise GatewayError(msg)
def test_timestamp_token(): envelope = load_xml(""" <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="https://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="https://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="https://schemas.xmlsoap.org/wsdl/" xmlns:wsu="https://schemas.xmlsoap.org/ws/2003/06/utility" xmlns:xsd="https://www.w3.org/2001/XMLSchema" > <soap-env:Header xmlns:ns0="https://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <ns0:Security> <ns0:UsernameToken/> </ns0:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """) # noqa timestamp_token = WSU.Timestamp() timestamp_token.attrib["Id"] = "id-21a27a50-9ebf-49cc-96bf-fcf7131e7858" some_date_obj = datetime.datetime(2018, 11, 18, 15, 44, 27, 440252) timestamp_elements = [ WSU.Created(some_date_obj.strftime("%Y-%m-%dT%H:%M:%SZ")), WSU.Expires( (some_date_obj + datetime.timedelta(minutes=10)).strftime("%Y-%m-%dT%H:%M:%SZ")), ] timestamp_token.extend(timestamp_elements) token = UsernameToken("Vishu", "Guntupalli", timestamp_token=timestamp_token) envelope, headers = token.apply(envelope, {}) expected = """ <soap-env:Envelope xmlns:ns0="http://example.com/stockquote.xsd" xmlns:soap="https://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap-env="https://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="https://schemas.xmlsoap.org/wsdl/" xmlns:wsu="https://schemas.xmlsoap.org/ws/2003/06/utility" xmlns:xsd="https://www.w3.org/2001/XMLSchema"> <soap-env:Header xmlns:ns0="https://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <ns0:Security> <ns0:UsernameToken> <ns0:Username>Vishu</ns0:Username> <ns0:Password Type="https://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Guntupalli</ns0:Password> </ns0:UsernameToken> <wsu:Timestamp xmlns:wsu="https://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" Id="id-21a27a50-9ebf-49cc-96bf-fcf7131e7858"> <wsu:Created>2018-11-18T15:44:27Z</wsu:Created> <wsu:Expires>2018-11-18T15:54:27Z</wsu:Expires> </wsu:Timestamp> </ns0:Security> </soap-env:Header> <soap-env:Body> <ns0:TradePriceRequest> <tickerSymbol>foobar</tickerSymbol> <ns0:country/> </ns0:TradePriceRequest> </soap-env:Body> </soap-env:Envelope> """ # noqa assert_nodes_equal(envelope, expected)