Open Puliczek opened 5 years ago
Hi @Puliczek, as you could notice this branch is an proof of concept for expected solution (making calls to CSIOZ API to save e-recepta).
Currently you can take a look into this class: https://github.com/konczak/erecepta-poc-first/blob/master/ereceptapoc/src/main/java/pl/konczak/nzoz/ereceptapoc/soaprequesttool/WSSecurityHandler.java and the original source of it: https://sourceforge.net/p/signsoaprequest/code/HEAD/tree/SignSOAPRequest/trunk/src/main/java/br/gov/dataprev/soaptools/sign/
however it doesn't do exactly what you are asking about "sign kontekstWywolania header". As far as I understood while making call to CSIOZ API we need to sign body of request as patient treatment station using given certificate and apply calculated signature as part of SOAP request headers compliant to WS-Security and Token Profile which also includes public part of certificate. So as kontekstWywolania is part of headers we do not calculate signature from it - fix me if I'm wrong on that.
Currently solution creates SoapMessage class which printed as String seems to be correct because is in structure compliant to SOAP-UI sample - just calculated data are different as expected. However when send that request to CSIOZ it results with server error HTTP 500. I have already emailed them about it but still didn't receive answer what is wrong about my request.
I'm not an expert from SOAP client requests so tried to use an very low level solution with just concat Strings into XML + HTTP request but signatures occured to be a bit tricky. Currently I have made research what are the options for more efficient client side handling and so I'm learning Apache CXF which believe will also use WSS4j to handle WS-Security part - but I'm far from the finals yet.
PS. If it is not a secret share some info how you have got to this repo and what you are tring to achive :D
I have found your repo via search bar on github. Using "erecepta" query.
My main goal is to send and receive msg to CSIOZ API for erecepta.
Yeah, I started my project with Apache CXF but had some other problems... So I decided to go with your code. Normally I work in .net world, so my knowledge about WS and SOAP in Java is too weak.
I have discovered some issues with your code:
1) You probably have to add header to your CsiozClient.java
httpPost.addHeader("SOAPAction", "urn:zapisPakietuRecept");
2) You probably have to use random id in WSS parameter - ws-id
public Document signSoapMessage(SOAPMessage message) {
try {
Document doc = message.getSOAPBody().getOwnerDocument();
Crypto crypto = CryptoFactory.getInstance(properties); //File
WSSecSignature sign = new WSSecSignature();
sign.setUserInfo(properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.alias"), properties.getProperty("privatekeypassword"));
sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE); // Binary Security Token - SecurityTokenReference
sign.setUseSingleCertificate(true);
sign.setDigestAlgo(DigestMethod.SHA1);
// --- way better wsu:id ( instead of 'id-1' there is 'id-EIJDW201394832049234' )
WsuIdAllocator idAllocator = new WsuIdAllocator() {
public String createId(String prefix, Object o) {
return "id-" + UUIDGenerator.getUUID();
}
public String createSecureId(String prefix, Object o) {
return "id-" + UUIDGenerator.getUUID();
}
};
WSSConfig wsConfig = new WSSConfig();
wsConfig.setIdAllocator(idAllocator);
sign.setWsConfig(wsConfig);
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(doc);
//We don't need this
//secHeader.setMustUnderstand(true);
Document signedDoc = sign.build(doc, crypto, secHeader);
return signedDoc;
} catch (SOAPException e) {
e.printStackTrace();
return null;
} catch (WSSecurityException e) {
e.printStackTrace();
throw new RuntimeException("Error: " + e.getMessage());
}
}
3) Soap Headers is not signed. Here is my comparison with SoupUi
I think we just need to sign this header to have working poc. However, I didn't figure out how to do it.
Thanks for help.
Ok, I have solved the last problem.
1) You have to setX509cert 2) Sign kontekstWywolania soap Header ( yeah I know that in CSIOZ documentation there are only words about signing body content but it is not true )
Right now I have Http 200 answer from CSIOZ.
If you need any help just get in touch.
So let's go first through points from earlier anser:
- You probably have to add header to your CsiozClient.java httpPost.addHeader("SOAPAction", "urn:zapisPakietuRecept");
thank you very much - I have missed that - set an Content-Type header but missed SOAPAction - will add it as well.
You probably have to use random id in WSS parameter - ws-id yeah definitely - for start and proof of concept it was just enough for me and also made it easier to debug result and link signature and signed element.
Soap Headers is not signed. Here is my comparison with SoupUi
I have no idea how I could missed that during compare of code result and SoapUI - petty that it is missed in documentation. Maybe they assumed that if mentioned that request has to be signed we will find out that everything has to be secured. At some moments I have that strange feeling that they are repeating some encryptions and signups requirements accross single request :/ especially that anyway everything has to go through TLS and 2 way auth.
And now about next answer - that is awesome that you have find out a way to handle that - I guess that code is secret so won't ask about it 馃槣
- You have to setX509cert
Sounds reasonable - strange that it didn't throw an exception during preparing singature though public part of certificate has to be applied to request.
- Sign kontekstWywolania soap Header ( yeah I know that in CSIOZ documentation there are only words about signing body content but it is not true )
well as you have mentioned it has worked for you and SoapUI does the same - now I also see that message send via SoapUI contains multiple references inside signature. If it is not a problem a tip how you have manage to sign other parts is welcome seen 馃槃
At some moments I have that strange feeling that they are repeating some encryptions and signups requirements accross single request :/ especially that anyway everything has to go through TLS and 2 way auth.
Sometimes I feel that the whole CSIOZ e-recepta API is only to get things harder... No code examples, only theory in the documentation...
And now about next answer - that is awesome that you have find out a way to handle that - I guess that code is secret so won't ask about it stuck_out_tongue_winking_eye
Here is my question and answer: https://stackoverflow.com/questions/56701257/wsse-sign-an-element-inside-soapenvheader
Sounds reasonable - strange that it didn't throw an exception during preparing singature though public part of certificate has to be applied to request.
No worries, you will get 10+ errors after successive connection with CSIOZ. :P
Right now I am fighting with several issues with my xml. For example the wrong id of a drug? I don't know why, because it is an offical example from CSIOZ -.-
I have checked your question and answer in StackOverflow and understood that you have altered code from wss4j to add your own to sign part of SOAP header. However did you really used ("something","somethingNamespace","") for the part? And did it work? Or it is just placeholder? Because I would believe that after specify namespace of "v201" where "kontekstWywolania" exists it could work.
About errors after successful connection - I expect them because even right now SoapUI project does not work and returns errors and validation warnings - and there is a lot of them. Server rejects my requests claiming that identified company does not match they record (address is different). Also it returns multiple errors about used medicaments that they are not known - while actually I'm using their sample project 馃檮 I have identified that some data could be found under those files: Rejestr_Produktow_Leczniczych_stan_na_dzien_20190208230018.xml SOLR_LR-I-20190501-4282.xml but as long as they are only warnings I'm ignoring them 馃槢
Thanks for info about using BST - definitely it is incorrect - it shuld be set to use X509 certificate and apply only public part of certificate inside request signature.
I have also found out info about CXF and wss4j: http://ws.apache.org/wss4j/using.html http://www.itzone.pl/articles/java/cxf_ws_security.php that when using outgoing message interceptor we can specify what parts should be signed/encrypted like:
<entry key="signatureParts" value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
I think it can be useful for our case as well - just need to find a way how to apply this to WSSecSignature config - maybe properties are the way.
I have checked your question and answer in StackOverflow and understood that you have altered code from wss4j to add your own to sign part of SOAP header. However did you really used ("something","somethingNamespace","") for the part? And did it work? Or it is just placeholder?
No, those are fakes, exact working values:
WSEncryptionPart aaa = new WSEncryptionPart("kontekstWywolania","http://csioz.gov.pl/p1/kontekst/mt/v20170510","");
Server rejects my requests claiming that identified company does not match they record (address is different).
Yeah, the server is going to validate everything: IDs, Address, Regon14, etc.
Also it returns multiple errors about used medicaments that they are not known - while actually I'm using their sample project 馃檮 I have identified that some data could be found under those files: Rejestr_Produktow_Leczniczych_stan_na_dzien_20190208230018.xml SOLR_LR-I-20190501-4282.xml but as long as they are only warnings I'm ignoring them 馃槢
Right now I am struggling with this problem. I have to check those files. Thanks.
Thanks for info about using BST - definitely it is incorrect - it shuld be set to use X509 certificate and apply only public part of certificate inside request signature.
Btw. You can always use or check podpisKwalifikowany-1.4.1.jar from SoupUi CSIOZ's sample project. There is an answer on how to sign XML in a proper way.
I have also found out info about CXF and wss4j: http://ws.apache.org/wss4j/using.html http://www.itzone.pl/articles/java/cxf_ws_security.php that when using outgoing message interceptor we can specify what parts should be signed/encrypted like:
I think it can be useful for our case as well - just need to find a way how to apply this to WSSecSignature config - maybe properties are the way.
Cool, I think that this solution can save us from editing official Apache library :P Nevertheless, as I mentioned on StackOverflow, there is probably a bug in Apache library, in terms of adding extra parts to encode in programmatically way.
Hi @Puliczek as already mentioned I have been looking for more correct Java solution than manual handling of SOAPs with e-recepta WS and so I have created this repository: https://github.com/konczak/erecepta it uses Apache CXF as SOAP client engine.
At the current stage it still does not work (it is impossible to create e-recepta in server) and it is like few steps back comparing to this project (need to solve same problems) but I will apply required steps with time up there.
If you wish to still monitor my progress probably will like to add watch over https://github.com/konczak/erecepta repository.
Best regards
Hi! It's my solution to generate property signature o header based on previous messages. @konczak @Puliczek Thanks!
public Document signSoapMessage(SOAPMessage message) {
try {
Document doc = message.getSOAPBody().getOwnerDocument();
Crypto crypto = CryptoFactory.getInstance(properties); //File
WSSecSignature sign = new WSSecSignature();
sign.setUserInfo(properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.alias"), properties.getProperty("privatekeypassword"));
sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE); // Binary Security Token - SecurityTokenReference
sign.setUseSingleCertificate(true);
sign.setDigestAlgo(DigestMethod.SHA1);
// dodanie generatora id
WsuIdAllocator idAllocator = new WsuIdAllocator() {
public String createId(String prefix, Object o) {
return "id-" + UUIDGenerator.getUUID();
}
public String createSecureId(String prefix, Object o) {
return "id-" + UUIDGenerator.getUUID();
}
};
WSSConfig wsConfig = new WSSConfig();
wsConfig.setIdAllocator(idAllocator);
sign.setWsConfig(wsConfig);
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(doc);
// dodanie do podpisu kontekstu wywolania - bez tego podpisze jedynie Body!
List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
// kontekst wywolania
WSEncryptionPart kontekstWywolania = new WSEncryptionPart("kontekstWywolania","http://csioz.gov.pl/p1/kontekst/mt/v20170510","");
parts.add(kontekstWywolania);
// body
WSEncryptionPart bodyPart = new WSEncryptionPart(WSConstants.ELEM_BODY, WSConstants.URI_SOAP11_ENV, "");
parts.add(bodyPart);
sign.setParts(parts);
Document signedDoc = sign.build(doc, crypto, secHeader);
return signedDoc;
} catch (SOAPException e) {
e.printStackTrace();
return null;
} catch (WSSecurityException e) {
e.printStackTrace();
throw new RuntimeException("Error: " + e.getMessage());
}
}
//nie bede pisac po angielsku bo i tak program dla polakow @Martin89PL @konczak Panowie a macie co艣 do generowania dokument贸w recept hl7? Aktualnie robie to manualnie, ale oni tak du偶o zmian wprowadzaj膮, 偶e nie da si臋 nad膮偶y膰 za utrzymaniem...
Widzia艂em na drugim repo @konczak tworzenie modeli na podstawie xsd, ale serio nie da si臋 tego pro艣ciej zrobi膰?
@Puliczek Ja aktualnie jestem na etapie poprawnej komunikacji dla WyszukajReceptyWystawiaj膮cego czy jako艣 tak :) Nie ja zajmuj臋 si臋 podpisem recept. Tworzeniem dokument贸w pewnie zajm臋 si臋聽tak od poniedzia艂ku :/ Tak偶e dopiero do tego przysi膮d臋.
Hej, @Martin89PL gratuluj臋 opracowania rozwi膮zania do podpisywania request贸w SOAP praktycznie od zera :)
Ja zrezygnowa艂em z w艂asnego rozwi膮zania na rzecz Apache CXF.
@Puliczek W repo i branch: https://github.com/konczak/erecepta/tree/update-erecepta-generation znajdziesz kod kt贸ry pozwala na pe艂n膮 obslug臋 e-recepty tzn:
PS. To repo ju偶 raczej nie b臋d臋 kontynuowa艂 - by艂 to raczej PoC. PS2. To drugie repo musz臋 jeszcze posprz膮ta膰 w kodzie i zrobi膰 艂adnego publicznego mastera :) PS3. To drugie repo r贸wnie偶 nie jest finalnym - zawiera jedynie kod przygotowania e-recepty - aplikacja kt贸ra robi znacznie wi臋cej a wystawianie e-recept b臋dzie jedynie jej modu艂em jest w prywatnym repo. PS4. Bardzo mo偶liwe 偶e w tym drugim repo jeszcze b臋d臋 walczy艂 z aktualizacj膮 dokumentu e-recepty bo CSIOZ aktualnie wprowadza nowe wymogi odno艣nie walidacji bloku narracyjnego (nareszcie) https://ezdrowie.gov.pl/portal/artykul/wprowadzenie_walidacji_bloku_narracyjnego_dokumentu_e-recepty_-_aktualizacja - ale czekam na co艣 bardziej stabilnego. PS5. W drugim repo u偶y艂em Apache CXF i JAXB do generowania modelu HL7 i sko艅czy艂em z manualnymi zmianami :( Inny develop pisa艂 偶e on u偶ywa XmlBeans i jest zadowolony - zdecydowanie rozwa偶am mo偶liwo艣膰 przesiadki - i najpewniej pr贸by znajd膮 si臋 w drugim repo.
@konczak No w艂a艣nie podgl膮da艂em Twoje drugie repo, kawa艂 dobrej roboty tam zrobi艂e艣. Dzi臋ki za podzielenie si臋 wiedz膮.
PS2. ooo to ja czekam :) PS4 (te偶 wole od xboxa). No super, ale to juz powinno by膰 p贸l roku temu wprowadzone, A nie 3 tygodnie przed wymogiem wejscia na produkcji przychodni... Jest gotowa transformata do tego, j膮 mo偶na u偶y膰 do stworzenia gotowego textu na podstawie xml e-recepty. PS5. Obadam tego XmlBeans ale wydaje mi si臋 偶e nie b臋dzie tam jakiego艣 super u艂atwienia.
Ja og贸lnie mam napisane wi臋kszo艣膰 systemu ju偶 pod obs艂ug臋 e-recept no ale co z tego skoro CSIOZ co chwile wprowadza zmiane i zaczynaja wyskakiwa膰 b艂臋dy REG z API kt贸rych nie ma na najnowszej wersji P1-DS-Z5-Lista_regul_P1.xlsx
Gdyby kto艣 z was by艂 zainteresowany wymian膮 wiedzy na temat pisania program贸w dla przychodni to stworzy艂em grup臋 na facebook-u: https://www.facebook.com/groups/598282080920579/ Nie mog艂em znale藕膰 innego miejsca, gdzie mog臋 wymienia膰 si臋 wiedz膮 na ten temat, nie tylko o CSIOZ. A temat贸w b臋dzie coraz wi臋cej :P
艢wietne repo i dobra dyskusja. Zastanawia艂em si臋 jeszcze nad generowaniem zamiast z xsd z plik贸w decor. Wpad艂em na taki filmik szukaj膮c informacji o tego typu narz臋dziach z CDA H7, co ciekawe jest tam nawet wspomniana implementacja z PL, tam generuja z plik贸w .MIF, kt贸re to przez CSIOZ nie s膮 udost臋pniane. P贸ki co bez sukces贸w.
Znalazlem tez ich repo na githubie - https://github.com/MohawkMEDIC/everest/tree/master
Ja pad艂em jak wprowadzili generowanie sekcji czytelnej z transformaty. Nie mog艂em pozby膰 si臋 problem贸w walidacji. Generalnie projekt zosta艂 przerwany - ilo艣膰 czasu potrzebnego na dostarczenie rozwi膮zania przeros艂a moje oczekiwania.
Tak to racja, mi si臋 uda艂o zrobi膰 e-recepty, e-skierowania, e-deklaracja, baze lek贸w. Ale czas jaki trzeba by艂o na to po艣wi臋ci膰 jest ogromny ;( Setki godzin... Jedna z gorszych integracji jakie przysz艂o mi pisa膰. Na si艂e utrudniana przez tw贸rc贸w, b艂臋dy w dokumentacji, brak przyk艂ad贸w kodu.
@Puliczek a najlepsze w tym wszystkim jest to 偶e po calej implementacji wprowadzaj膮 zmiany/ulepszenia struktur i po艂owa roboty od nowa :(
Zastanawialem sie tez nad projektem opensource z bibliotekami javy/c#/php czy cokolwiek na co by chetni do pisania byli z implementacja konkretnej wersji hl7 i innych struktur xml zeby dla kazdego chetnego pozostawala implementacja samej logiki biznesowej bez szarpania sie ze wszystki wywolaniami. Ewentualnie zebrac sie i napisac platne biblioteki i dzielic zarobkami ze sprzedazy (moze nawet sam NFZ by zakupil takie cos :) )
Tez myslalem o tym, ale masz odpowiedz z tym repo ile osob by robilo update :) A komercyjnie sie nie oplaca bo juz sam tworca P1 czyli Pentacomp sprzedaje "Platforma e-Zdrowia" czyli API do latwieszego wystawiania e-recept itp. :) To sa dopiero jaja, a drogie w cholere raczej liczcie w dziesi膮tkach tysi臋cy rocznie :D
Hi,
Did you manage to sign kontekstWywolania header in WSS4j?