Cześć, Piszę prostą aplikację do wymiany informacji z PUESC. Niestety utknąłem na próbie skomunikowania się z PUESC-em. Co ciekawe, skonfigurowane SoapUI bez problemu łączy się z serwisem. Mój kod jest w Pythonie (z góry przepraszam za jego jakość), ale jak widać Łączenie się z WebService SEAP w PUESC problem jest szerszy.
Co do tej pory udało mi się ustalić:
- Jeśli szybko "przekleję" wygenerowany przez Soap UI request do mojego kodu w pythonie(w miejsce xmla)
to serwis odpowiada poprawnie - Podejrzewam że problem leży w generowaniu UsernameToken lub MessageID
- Support PUESC olewa temat
Może ktoś z Was ma jakiś pomysł gdzie lezy problem? Albo udało mu się rozwiązać problem w innym języku.
Poniżej link do dokumentacji usługi:
https://puesc.gov.pl/documents/20123/603192553/PUESCKUD_SEAP_XML_PL.pdf/1553ee91-140b-56f3-d9e1-fc1bb1d39220?t=1623411653806
import base64
import hashlib
import json
import secrets
import uuid
from datetime import datetime
import pytz
import requests
from requests.structures import CaseInsensitiveDict
from xml.dom import minidom
def load_credentials(filename):
with open(filename, "r") as file:
return json.load(file)
def generate_nonce(size=16):
return secrets.token_bytes(size)
def sha1_base64(data):
return base64.b64encode(hashlib.sha1(data).digest()).decode("utf-8")
def construct_password_digest(nonce, created, password):
password_sha1_base64 = sha1_base64(password.encode("utf-8"))
data_to_digest = (
nonce + created.encode("utf-8") + password_sha1_base64.encode("utf-8")
)
return sha1_base64(data_to_digest)
def prepare_soap_request(url, headers, login, password, nonce, created_date):
message_id = f"uuid:{uuid.uuid4()}"
user_name_token = f"UsernameToken-{uuid.uuid4()}"
password_digest_base64_encoded = construct_password_digest(
nonce, created_date, password
)
nonce_base64_encoded = base64.b64encode(nonce).decode("utf-8")
xml = f"""
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:_v2="http://www.mf.gov.pl/uslugiBiznesowe/WsPull/Usluga/2014/01_v2_0">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsse:Security soapenv:mustUnderstand="1"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="{user_name_token}">
<wsse:Username>{login}</wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
{password_digest_base64_encoded}</wsse:Password>
<wsse:Nonce
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
{nonce_base64_encoded}</wsse:Nonce>
<wsu:Created>{created_date}</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
<wsa:Action soapenv:mustUnderstand="1">GetNextDocument</wsa:Action>
<wsa:MessageID soapenv:mustUnderstand="1">{message_id}</wsa:MessageID>
</soapenv:Header>
<soapenv:Body>
<_v2:GetNextDocumentRequest>
</_v2:GetNextDocumentRequest>
</soapenv:Body>
</soapenv:Envelope>
"""
response = requests.post(url, headers=headers, data=xml)
return response
if __name__ == "__main__":
credentials = load_credentials("env.json")
login = credentials["login"]
password = credentials["password"]
nonce = generate_nonce()
created_date = datetime.now(pytz.timezone("UTC")).strftime("%Y-%m-%dT%H:%M:%SZ")
url = "https://te-ws.puesc.gov.pl/seap_wsChannel/DocumentHandlingPort"
headers = CaseInsensitiveDict()
headers["Content-Type"] = "text/xml;charset=UTF-8"
headers["SOAPAction"] = "GetNextDocument"
response = prepare_soap_request(url, headers, login, password, nonce, created_date)
xml_pretty = minidom.parseString(response.text).toprettyxml()
print(xml_pretty)
Przykładowa odpowiedź serwisu generowana po wywołaniu kodu powyżej:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Action xmlns="http://www.w3.org/2005/08/addressing">http://www.mf.gov.pl/uslugiBiznesowe/WsPull/Usluga/2014/01_v2_0/DocumentHandlingPort/GetNextDocument/Fault/WSSecurityException</Action>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:614444538-33df-48bc-afc4-6459039e1a31</MessageID>
<To xmlns="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/anonymous</To>
<RelatesTo xmlns="http://www.w3.org/2005/08/addressing">uuid:0bbeb7c0-ba33-43be-9407-03ffce97b121</RelatesTo>
</soap:Header>
<soap:Body>
<soap:Fault>
<faultcode xmlns:ns1="http://ws.apache.org/wss4j">ns1:SecurityError</faultcode>
<faultstring>A security error was encountered when verifying the message</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Poniżej odpowiedź generowana po zapytaniu przez Soap UI:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Action xmlns="http://www.w3.org/2005/08/addressing">http://www.mf.gov.pl/uslugiBiznesowe/WsPull/Usluga/2014/01_v2_0/DocumentHandlingPort/GetNextDocumentResponse</Action>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:6ac7d983-62f5-4ba9-a390-d16596d5ac0d</MessageID>
<To xmlns="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/anonymous</To>
<RelatesTo xmlns="http://www.w3.org/2005/08/addressing">uuid:d4533c17-81f0-4039-b7a7-ba1466582c37</RelatesTo>
</soap:Header>
<soap:Body>
<ns2:GetNextDocumentResponse hasNext="false" xmlns="http://www.mf.gov.pl/schematy/SISC/WsChannel/2014/01_v2_0" xmlns:ns2="http://www.mf.gov.pl/uslugiBiznesowe/WsPull/Usluga/2014/01_v2_0"/>
</soap:Body>
</soap:Envelope>