{"id":2234,"date":"2014-06-09T18:34:32","date_gmt":"2014-06-09T15:34:32","guid":{"rendered":"http:\/\/9v.lt\/blog\/?p=2234"},"modified":"2022-01-19T08:34:39","modified_gmt":"2022-01-19T06:34:39","slug":"viisp-tapatybes-nustatymo-paslauga","status":"publish","type":"post","link":"https:\/\/9v.lt\/blog\/viisp-tapatybes-nustatymo-paslauga\/","title":{"rendered":"VIISP tapatyb\u0117s nustatymo paslauga"},"content":{"rendered":"<p>Sveiki :)<br \/>\n\u0160\u012f kart\u0105 nor\u0117\u010diau apra\u0161yti apie fain\u0105 dalyk\u0117l\u012f i\u0161 VIISP (elektroniniai vald\u017eios vartai, anks\u010diau vadinosi VAIISIS), kur\u012f naudoja daug \u017emoni\u0173, \u012fskaitant rajon\u0173, apylinki\u0173 ir miesteli\u0173 svetaines &#8211; tai yra tapatyb\u0117s nustatymo ir patvirtinimo paslauga kuri vyksta identifikavusis per bankus, asmens tapatyb\u0117s kortele ir pana\u0161iai. Daug yra panaudojimo galimybi\u0173&#8230;<br \/>\nIstorijos kod\u0117l a\u0161 su \u0161ita sistema u\u017esi\u0117miau nepasakosiu, tiesiog papasakosiu kaip man pavyko \u012fdiegti \u0161i\u0105 paslaug\u0105.<br \/>\n<strong>\u012eSP\u0116JIMAS: neatsakau u\u017e padarytus pakeitimus IVPK projektuose, nuorodose ar oficialioje dokumentacijoje kurie buvo padaryti po straipsnio publikavimo datos.<\/strong><br \/>\n<!--more--><br \/>\nVisk\u0105 suskirstau \u012f grupes. Papasakosiu apie tapatyb\u0117s nustatymo paslaug\u0105, reikaling\u0105 med\u017eiag\u0105, resursus, pavyzd\u017eius i\u0161 VIISP ir pateiksiu savo pavyzdin\u012f kod\u0105 su PHP :)<\/p>\n<p>Taigi, prad\u0117kime. \u0160tai pristatomas filmukas:<br \/>\n<iframe loading=\"lazy\" title=\"Valstyb\u0117s informacini\u0173 i\u0161tekli\u0173 s\u0105veikumo platforma (VIISP)\" width=\"810\" height=\"456\" src=\"https:\/\/www.youtube.com\/embed\/6vGAP4nirC4?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe><\/p>\n<p>Pati paslauga yra nemokama, tik reikia pasira\u0161yti sutart\u012f. Naudojantis \u0161ia paslauga galima gauti tokius duomenis kaip vardas, pavard\u0117, gimimo data, asmens kodas&#8230;<\/p>\n<p><a href=\"https:\/\/www.epaslaugos.lt\/portal\/provider\/content\/1257\" target=\"_blank\" rel=\"noopener noreferrer\">\u0160ioje skiltyje<\/a> galima rasti informacijos kokios mums reik\u0117s.<br \/>\n<a href=\"https:\/\/www.epaslaugos.lt\/portal\/file\/c771b438-9393-41fe-90a1-70d2745d660b\" target=\"_blank\" rel=\"noopener noreferrer\">Tapatyb\u0117s nustatymo specifikacijoje<\/a> apra\u0161yta viskas kaip veikia, kas k\u0105 perduoda ir kaip k\u0105 si\u0173sti, o <a href=\"https:\/\/www.epaslaugos.lt\/portal\/file\/37cea127-c44d-444f-b1b1-54da655b243a\" target=\"_blank\" rel=\"noopener noreferrer\">\u010dia \u0161ioks toks tutorial&#8217;as<\/a> para\u0161ytas pa\u010di\u0173 IVPK \u017emoni\u0173, kuris mano nuomone, gal\u0117t\u0173 b\u016bti i\u0161samesnis. Prisegtas yra ir <a href=\"https:\/\/www.epaslaugos.lt\/portal\/file\/4ee4d4d7-431b-4e5c-ad65-c0bd8f32dbec\" target=\"_blank\" rel=\"noopener noreferrer\">Java projektas, skirtas para\u0161o generavimui<\/a> kuris yra pagrindinis dalykas \u0161itam reikale, apie j\u012f kiek \u017eemiau apra\u0161ysiu.<\/p>\n<p>Panagrin\u0117kime \u0161iek tiek specifikacij\u0105.<\/p>\n<p><img decoding=\"async\" src=\"\/blog\/filemgmt\/uploads\/ivairios\/Hrrmvzv.png\" alt=\"vaiisis_1\" \/><\/p>\n<p>\u017di\u016brint \u012f \u0161it\u0105 diagram\u0105, paimt\u0105 i\u0161 dokumento, matosi k\u0105 reikia si\u0173sti ir kas yra gr\u0105\u017einama, ir matosi kad visos u\u017eklausos yra daromos per POST&#8217;\u0105. Ta\u010diau man daug nerv\u0173 kainavo bandant siuntin\u0117ti biliet\u0105 per POST&#8217;\u0105 kol buvo pasi\u016blyta tiesiog naudoti GET&#8217;\u0105, kas mano atveju suveik\u0117 puikiai. Vis vien yra siuntin\u0117jama unikalus bilietas tai koks skirtumas kokiu b\u016bdu si\u0173si&#8230;<\/p>\n<p>I\u0161 diagramos gal nesimato, ta\u010diau identifikacija vyksta dviem etapais. Pirmu etapu yra inicijuojama identifikacija, siun\u010diama XML&#8217;u pilnai suformuota u\u017eklausa, su para\u0161u ir kitokia informacija. Jei pasitvirtina, gaunamas XML&#8217;o atsakymas su mums taip reikalingu unikaliu bilietu kuris galioja neilgai. T\u0105 biliet\u0105 i\u0161traukus i\u0161 gauto XML&#8217;o reikia si\u0173sti \u012f VIISP ir \u010dia prasideda antras etapas. Vartotoj\u0105 redirect&#8217;inam kartu su bilietu GET&#8217;e, o toliau tik laukiam atsakymo.<br \/>\nKai vartotojas identifikuojasi ir Vald\u017eios vartuose paspaud\u017eia &#8220;Patvirtinti&#8221;, j\u012f nukreipia \u012f m\u016bs\u0173 nustatyt\u0105 Postback URL kartu su to \u017emogaus duomenimis XML formate.<\/p>\n<p>Dabar b\u016bt\u0173 geras metas parsip\u016bsti <a href=\"http:\/\/www.eclipse.org\/downloads\/packages\/eclipse-standard-432\/keplersr2\" target=\"_blank\" rel=\"noopener noreferrer\">Eclipse<\/a> jei dar neturi ir \u012fsikelti Java projekt\u0105 min\u0117t\u0105 auk\u0161\u010diau.<br \/>\nProjektas generuoja pasira\u0161yt\u0105 XML&#8217;\u0105 pagal turim\u0105 sertifikat\u0105 ir privat\u0173 rakt\u0105 kurie \u012fdedami \u012f &#8220;Java Keystore&#8217;\u0105&#8221;, paprastai tariant \u012f konteiner\u012f su spyna kur saugoma sertifikatas ir privatus raktas, bet tai padaryti n\u0117ra tiesiogiai paprasta kaip pamatysime v\u0117liau.<\/p>\n<p>Taigi atsidarom <em>AuthGenerator.java<\/em> klas\u0119, kuri generuoja para\u0161\u0105 pirmam etapui ir matom:<\/p>\n<pre lang=\"java\">\r\nprivate void generateRequest() throws Exception {\r\n\tAuthenticationRequestXml request = new AuthenticationRequestXml();\r\n\trequest.setId(SIGNED_NODE_ID);\r\n\trequest.setPid(PID);\r\n\trequest.setCustomData(\"correlationData\");\r\n\trequest.setPostbackUrl(\"https:\/\/localhost\");\r\n\trequest.getAuthenticationAttribute().add(AuthenticationAttribute.LT_PERSONAL_CODE);\r\n\trequest.getAuthenticationAttribute().add(AuthenticationAttribute.LT_COMPANY_CODE);\r\n\trequest.getAuthenticationProvider().add(AuthenticationProviderXml.AUTH_PROVIDER_LT_IDENTITY_CARD);\r\n\trequest.getAuthenticationProvider().add(AuthenticationProviderXml.AUTH_PROVIDER_LT_BANK);\r\n\trequest.getAuthenticationProvider().add(AuthenticationProviderXml.AUTH_PROVIDER_SIGNATURE);\r\n\trequest.getAuthenticationProvider().add(AuthenticationProviderXml.AUTH_PROVIDER_LOGIN_PASS);\r\n\/\/\t\trequest.setServiceTarget(ServiceTargetXml.SERVICE_TARGET_BUSINESS);\r\n\trequest.getUserInformation().add(UserInformation.FIRST_NAME);\r\n\trequest.getUserInformation().add(UserInformation.LAST_NAME);\r\n\trequest.getUserInformation().add(UserInformation.COMPANY_NAME);\r\n\r\n\tDocument doc = (Document) marshal(request);\r\n\tString xml = getSignedXml(doc.getFirstChild(), \"#\" + request.getId());\r\n\r\n\tSystem.out.println(\"Auth request XML, which goes directly into SOAP body (Note: whitespace is important!):\\n\");\r\n\tSystem.out.println(StringUtils.substringAfter(xml, \"?>\"));\r\n}\r\n<\/pre>\n<p>Labai daug prira\u0161yta, tad paai\u0161kinsiu kokios eilut\u0117s k\u0105 daro.<br \/>\nPirma <code>request.setId(SIGNED_NODE_ID);<\/code> nustato j\u016bs\u0173 u\u017eklausos ID. Jis visai proced\u016brai \u012ftakos neturi, tai gali vadintis kaip patogiau. Po default&#8217;u vadinasi <code>\"uniqueNodeId\"<\/code>.<\/p>\n<p>Toliau <code>request.setPid(PID);<\/code> nustato j\u016bs\u0173 identifikacin\u012f numer\u012f. Testavimo metu naudojamas <code>VSID000000000113<\/code>, ta\u010diau pasira\u0161ius sutart\u012f bus suteikiamas unikalus kur\u012f reik\u0117s \u012fra\u0161yti toje vietoje.<\/p>\n<p><code>request.setCustomData(\"correlationData\");<\/code> priima j\u016bs\u0173 Koreliacinius duomenis. Paprastai sakant, \u010dia galima \u012fra\u0161yti tai kas tur\u0117t\u0173 b\u016bti gra\u017einama kartu su atsakymu XML&#8217;e. Generuojant para\u0161\u0105 \u012fra\u0161ote koki\u0105 tai kintamojo reik\u0161m\u0119 ir po to gaunate t\u0105 pa\u010di\u0105 reik\u0161m\u0119 atgal. Tai patogus dalyk\u0117lis kai reikia ka\u017ek\u0105 pasi\u017eym\u0117ti darant u\u017eklaus\u0105 kad kai gra\u017einama \u017einotum\u0117t kas ir kur. Nes po redirect&#8217;o j\u016bs\u0173 skriptas pasibaigia&#8230;<\/p>\n<p><code>request.setPostbackUrl(\"https:\/\/localhost\");<\/code> va \u010dia yra tas PostBack URL. \u010cia nustatyti reikia kur vartotojas bus gra\u017einamas po to kai paspaus &#8220;Patvirtinti&#8221; vald\u017eios vartuose. Tur\u0117kit omen\u012f kad galima nurodyti ir URL be failo, kaip kad be index.php tarkime, tokiu b\u016bdu gal\u0117site naudoti PHP funkcijas, ta\u010diau <code>setPostbackUrl()<\/code> funkcijoje URL turi baigtis su slash&#8217;u (\/), kitaip u\u017eklausa nenukeliaus tinkamai.<\/p>\n<p>Toliau eina vartotojo atributai kuriuos norite gauti. \u0160iaip u\u017etenka tik palikti <code>request.getAuthenticationAttribute().add(AuthenticationAttribute.LT_PERSONAL_CODE);<\/code> ir gausite asmens kod\u0105.<\/p>\n<p>Toliau, <code>request.getAuthenticationProvider().add()<\/code> nustato kokiais b\u016bdais leisite vartotojui identifikuotis. M\u016bs\u0173 projektui u\u017eteko tik bank\u0173, tai ir palikome tik <\/p>\n<pre>request.getAuthenticationProvider().add(AuthenticationProviderXml.AUTH_PROVIDER_LT_BANK);<\/pre>\n<p><code>request.getUserInformation().add()<\/code> prideda kokius norite duomenis gauti apie vartotoj\u0105. V\u0117lgi m\u016bs\u0173 projektui pakako vardo, pavard\u0117s ir gimimo datos, plius asmens kodas. Tod\u0117l palikome:<br \/>\n<code>request.getUserInformation().add(UserInformation.FIRST_NAME);<br \/>\nrequest.getUserInformation().add(UserInformation.LAST_NAME);<br \/>\nrequest.getUserInformation().add(UserInformation.BIRTHDAY);<\/code><\/p>\n<p>Toliau kodas \u0161ioje klas\u0117je neaktualus. Sugeneruota XML u\u017eklausa (mano atveju) atrodo taip (suformatuota d\u0117l geresnio skaitomumo):<\/p>\n<pre lang=\"xml\">\r\n<authentication:authenticationRequest xmlns:authentication=\"http:\/\/www.epaslaugos.lt\/services\/authentication\" xmlns:dsig=\"http:\/\/www.w3.org\/2000\/09\/xmldsig#\" xmlns:ns3=\"http:\/\/www.w3.org\/2001\/10\/xml-exc-c14n#\" id=\"uniqueNodeId\">\r\n<authentication:pid>VSID000000000113<\/authentication:pid>\r\n<authentication:authenticationProvider>auth.lt.bank<\/authentication:authenticationProvider>\r\n<authentication:authenticationAttribute>lt-personal-code<\/authentication:authenticationAttribute>\r\n<authentication:userInformation>firstName<\/authentication:userInformation>\r\n<authentication:userInformation>lastName<\/authentication:userInformation>\r\n<authentication:userInformation>birthday<\/authentication:userInformation>\r\n<authentication:postbackUrl>http:\/\/localhost\/<\/authentication:postbackUrl>\r\n<authentication:customData\/>\r\n<Signature xmlns=\"http:\/\/www.w3.org\/2000\/09\/xmldsig#\">\r\n<SignedInfo>\r\n    <CanonicalizationMethod Algorithm=\"http:\/\/www.w3.org\/2001\/10\/xml-exc-c14n#\">\r\n    <InclusiveNamespaces xmlns=\"http:\/\/www.w3.org\/2001\/10\/xml-exc-c14n#\" PrefixList=\"authentication\"\/>\r\n<\/CanonicalizationMethod>\r\n<SignatureMethod Algorithm=\"http:\/\/www.w3.org\/2000\/09\/xmldsig#rsa-sha1\"\/>\r\n<Reference URI=\"#uniqueNodeId\">\r\n    <Transforms>\r\n        <Transform Algorithm=\"http:\/\/www.w3.org\/2000\/09\/xmldsig#enveloped-signature\"\/>\r\n        <Transform Algorithm=\"http:\/\/www.w3.org\/2001\/10\/xml-exc-c14n#\">\r\n        <InclusiveNamespaces xmlns=\"http:\/\/www.w3.org\/2001\/10\/xml-exc-c14n#\" PrefixList=\"authentication\"\/>\r\n    <\/Transform>\r\n<\/Transforms>\r\n<DigestMethod Algorithm=\"http:\/\/www.w3.org\/2000\/09\/xmldsig#sha1\"\/>\r\n<DigestValue>Qo6o54pUoVFMTLGgDIuHdF2K+54=<\/DigestValue>\r\n<\/Reference>\r\n<\/SignedInfo>\r\n<SignatureValue>OVLdU2Pi54KHYqqtzlqHl6eNL8O3Zx7DguvnLY9HO\/HkpUHZGiMgp5Lg\/k60LWyynN7XK3bYcgZv\r\nmTnXDduSVikYOhGp91Eh4xaWuolnn8e2o5kdAZK5PqiRbJ7eTGoyc7vU1Vv2WT81SH38sSAR4\/h2\r\nbNPc56+oVTbHAGyD3L++YZHWDrdaMZdJWvre\/HF5grzBfma0qMWTRm5PdHIKDCuzrkvUWI6A4Mv3\r\nFXAUQZPTLEaXrSP3yzQwV\/4rtCzPGxJ0vdvHzm6mn4Q+IQUutqtxpT2Fxl7E7FnoGMj45OReW4p\/\r\nGZnpo4Lx2Jt75B\/0j5BRbpHfdtbo+NkX3FZaRA==<\/SignatureValue>\r\n<KeyInfo>\r\n    <KeyValue>\r\n        <RSAKeyValue>\r\n            <Modulus>i+rh6NJ7Z6Q8XiMSVK\/Z8DYXIyk5j7N9GUX8AOSKONabse4us7\/ogR0x7OOf0FsrdxAhQls59Wn1\r\n            vDxujSVOu3v1JhML\/v\/WK8glcxM433oEEpb0C56XRHlt27Qkbsn6v3njC1z0NGyDFdAtg5PaMx7Y\r\n            mjyWR6ezMKj9wR5cK4CRZ7idm2PwzQaLUDFm7wUFXudZNkQ6pb60OvDw4ey1t68EVCPtq4nGdHG+\r\n            3jlSDTTJc\/03qk50pa6Nb\/t5+EWsE3jFt\/uhHim1rC2pMf5UrT26FL6\/DjA0PxQFecc76zeuv3xb\r\n            GSP7B7ubpG8fyatGb4oLB4eU0ceCJvqljGMP0w==<\/Modulus>\r\n            <Exponent>AQAB<\/Exponent>\r\n        <\/RSAKeyValue>\r\n    <\/KeyValue>\r\n<\/KeyInfo>\r\n<\/Signature>\r\n<\/authentication:authenticationRequest>\r\n<\/pre>\n<p><strong>Atkreipkit d\u0117mes\u012f<\/strong>, kad u\u017eklausoje neturi b\u016bti XML header&#8217;io (<code>&lt;?xml version=\"1.0\"?&gt;<\/code> ir pan.)<br \/>\nAntro etapo klas\u0117je <em>AuthDataRequestGenerator.java<\/em> nieko ypatingo, mus domina tik <code>dataRequest.setTicket(TICKET);<\/code> kur nusistato unikalus ID (vadinamas &#8220;bilietu&#8221; (ticket)) kuris buvo gautas i\u0161 serviso pirmu etapu.<\/p>\n<p>Tre\u010dioji ir paskutin\u0117 klas\u0117 yra <em>BaseAuthRequestGenerator.java<\/em> kuri\u0105 extend&#8217;ina kitos dvi. \u010cia vykdomas kodas tiek pat svarbus, tad atsidarius matome:<br \/>\n<code>public static final String SIGNED_NODE_ID = \"uniqueNodeId\";<\/code> nusistato Node ID, jis \u012ftakos neturi, tai galima palikti kaip yra. \u010cia tam kad patys atpa\u017eintum\u0117te gauto XML&#8217;o node&#8217;\u0105.<\/p>\n<p><code>private static final char[] PASSWORD = \"testtest\".toCharArray();<\/code> akivaizdu kad nustato slapta\u017eod\u012f keystore&#8217;o.<\/p>\n<p>Ir galiausiai <\/p>\n<pre>keyStore.load(FileUtils.openInputStream(FileUtils.toFile(AuthGenerator.class.getResource(\"\/testKeystore.jks\"))), PASSWORD);<\/pre>\n<p> yra kur naudojamas j\u016bs\u0173 Keystore&#8217;as.<\/p>\n<p>Tiek i\u0161 to Java projekto. M\u016bs\u0173 ma\u017eam projektui labai tiko ir Jar&#8217;as kvie\u010diamas generuoti para\u0161ui, tai mes ir pasinaudojome kas jau buvo duota, nereik\u0117jo perra\u0161in\u0117ti kad b\u016bt\u0173 native PHP. Jeigu pas jus projekto apsukos labai didel\u0117s, \u017einoma kviesti kas kart\u0105 Jar&#8217;\u0105 b\u016bt\u0173 didelis resurs\u0173 ir laiko \u0161vaistymas, ta\u010diau gal b\u016bt <a href=\"http:\/\/php-java-bridge.sourceforge.net\/pjb\/\">PHP-to-Java bridge&#8217;\u0105<\/a> eit\u0173 panaudoti \u0161iam reikalui.<br \/>\n<strong>Beje, tam kad veikt\u0173 \u0161is projektas<\/strong> jis turi b\u016bti leid\u017eiamas su Java7u21 (update 21) arba \u017eemesniu, kitais atvejais tiesiog gausite URIReferenceException&#8217;\u0105:<br \/>\n<code>javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID uniqueNodeId<\/code><br \/>\nParsisi\u0173sti reikiam\u0105 JDK versij\u0105 galite <a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/java-archive-downloads-javase7-521261.html#jdk-7u21-oth-JPR\" target=\"_blank\" rel=\"noopener noreferrer\">i\u0161 Oracle svetain\u0117s<\/a>, o kad i\u0161vengti tos kvailos registracijos, naudokite svetain\u0119 <a href=\"http:\/\/bugmenot.com\/view\/oracle.com\" target=\"_blank\" rel=\"noopener noreferrer\">bugmenot.com<\/a><\/p>\n<p>Dabar pakalb\u0117kime apie &#8220;Java Keystore&#8217;\u0105&#8221;. Pla\u010diau <a href=\"http:\/\/docs.oracle.com\/javase\/7\/docs\/api\/java\/security\/KeyStore.html\" target=\"_blank\" rel=\"noopener noreferrer\">oficialioje dokumentacijoje<\/a>.<br \/>\nNorint naudotis paslauga jums reik\u0117s susigeneruoti savo serverio sertifikat\u0105 ir privat\u0173 rakt\u0105, bei naudoti SSL. Pasira\u0161ant sutart\u012f j\u016bs\u0173 \u0161ito reikalaus vis tiek&#8230; tuos du dalyk\u0117lius reikia sud\u0117ti \u012f Keystore&#8217;\u0105, ta\u010diau tai n\u0117ra taip paprasta, nes Java keytool&#8217;as tokios funkcijos nepalaiko, kaip beb\u016bt\u0173 gaila. A\u0161 praleidau daug laiko kol i\u0161siai\u0161kinau kaip tai padaryti, kol galiausiai radau pora \u012franki\u0173 kurie padeda tai padaryti.<br \/>\nPora svetaini\u0173 kurios apra\u0161\u0117 \u0161\u012f metod\u0105 yra <a href=\"http:\/\/www.agentbob.info\/agentbob\/79-AB.html\" target=\"_blank\" rel=\"noopener noreferrer\">\u010dia<\/a> ir <a href=\"http:\/\/www.nealgroothuis.name\/import-a-private-key-into-a-java-keystore\/\" target=\"_blank\" rel=\"noopener noreferrer\">\u010dia<\/a>. \u0160iaip testuojant jau yra duotas jums testinis keystore&#8217;as, kuris yra sudarytas i\u0161 testavimui skirto sertifikato ir privataus rakto, kuriuos galima rasti <a href=\"https:\/\/www.epaslaugos.lt\/portal\/file\/96c4df14-53b7-4f11-8808-1da05fb729c2\" target=\"_blank\" rel=\"noopener noreferrer\">\u010dia<\/a>.<br \/>\nTestinio keystore&#8217;o alias&#8217;as yra &#8220;key&#8221;, o slapta\u017eodis &#8220;testtest&#8221;.<\/p>\n<p>Dabar tarkime kad norim pasidaryti savo Keystore&#8217;\u0105. Pirma reik <a href=\"http:\/\/www.openssl.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">\u012fsira\u0161yti OpenSSL<\/a> ir perdaryti *.pem failus \u012f *.der failus, tai padaroma su dviem komandom:<br \/>\n<code>openssl pkcs8 -topk8 -nocrypt -in key.pem -inform PEM -out key.der -outform DER<\/code><br \/>\n<code>openssl x509 -in cert.pem -inform PEM -out cert.der -outform DER<\/code><br \/>\nkonvertavus jau galima ir d\u0117ti \u012f keystore&#8217;\u0105, \u012frankius kuriuos reik naudoti <a href=\"\/blog\/filemgmt\/uploads\/files\/generate_keystore.zip\" target=\"_blank\" rel=\"noopener noreferrer\">galima gauti i\u0161 \u010dia<\/a>. A\u0161 pats naudojau <em>ImportKey.java<\/em>, kitas irgi veikia taip pat gerai. Kad tas Java kodas pasileist\u0173 j\u012f reik\u0117s sukompiliuoti, \u0161i\u0105 dal\u012f paliksiu jums i\u0161siai\u0161kinti ;)<br \/>\n<strong>Atkreipkit d\u0117mes\u012f<\/strong> kad slapta\u017eodis turi b\u016bti TIK i\u0161 ma\u017e\u0173j\u0173 raid\u017ei\u0173 ir grei\u010diausiai be skai\u010di\u0173. Atsitiktinumo keliu supratau kad keystore&#8217;as nors ir tinkamas, jo Java projektas ka\u017ekod\u0117l negali tinkamai atidaryti kai slapta\u017eodyje yra did\u017ei\u0173j\u0173 raid\u017eiu ir\/arba skai\u010di\u0173, tai kainavo man daug kantryb\u0117s kol supratau&#8230;<\/p>\n<p>Sugeneravus keystore&#8217;\u0105 galima j\u012f redaguoti toliau jei to reikia, gal norite pakeisti slapta\u017eod\u012f ar alias&#8217;\u0105&#8230; tam galima naudoti \u012frank\u012f <a href=\"http:\/\/portecle.sourceforge.net\/\" target=\"_blank\" rel=\"noopener noreferrer\">Portacle<\/a>, kuris yra tikrai geras dalykas tokiems darbams.<\/p>\n<p>Na k\u0105 gi, kad jau turime visk\u0105 ko reikia, galima siuntin\u0117ti u\u017eklausas. Kol vyksta bandymai, siuntin\u0117jama \u012f nuorodas su <em>-test<\/em> priera\u0161u, kaip kad:<br \/>\nWeb servisas: <code>https:\/\/www.epaslaugos.lt\/portal-test\/authenticationServices\/auth<\/code><br \/>\nAutentifikacijos URL: <code>https:\/\/www.epaslaugos.lt\/portal-test\/external\/services\/authentication\/v2\/<\/code><br \/>\nNormaliai siuntin\u0117jama \u012f tas pa\u010dias nuorodas tik be <em>-test<\/em>.<br \/>\nBeje jei bandote naudotis bankais testavimo metu, tai galima daryti tik su SEB ir Nordea, kiti tiesiog negra\u017eins atgal \u012f postBackURL().<\/p>\n<p>Atrodo kaip ir viskas, einam prie pabaigos. Galima vis\u0105 teorij\u0105 perkelti \u012f paprast\u0105 PHP kod\u0105. Tam para\u0161iau atskirus failus, <em>generateSignatureJava.php<\/em> kuri sugeneruoja ir gra\u017eina para\u0161\u0105, bei <em>vaiisis_test.php<\/em> kuris yra visa logika. Juos abu galima parsisi\u0173sti i\u0161 <a href=\"http:\/\/9v.lt\/projects\/php\/vaiisis.zip\" target=\"_blank\" rel=\"noopener noreferrer\">\u010dia<\/a>.<br \/>\nPHP kodas para\u0161o generavimui naudoja modifikuot\u0105 Java projekt\u0105 kur\u012f pakei\u010diau savo reikm\u0117ms kaip v\u0117liau pamatysite. Jeigu reik\u0117s gal\u0117siu \u012fkelt pavyzd\u012f :)<\/p>\n<p>Kas j\u0173 viduje?<br \/>\n<em>generateSignatureJava.php<\/em> atrodo taip:<\/p>\n<pre lang=\"php\">\r\n<?php\r\n\r\n\/**\r\n    Funkcija skirta sugeneruoti u\u017eklausos XML kuris bus siun\u010diamas\r\n    pradin\u0117je stadijoje inicijuojant autentifikavim\u0105.\r\n\r\n    @return:\r\n        String signedReqXML;\r\n*\/\r\nfunction generateReqXML() {\r\n    exec('\"C:\\Program Files\\Java\\jdk1.7.0_21\\bin\\java.exe\" -jar vaiisis.jar auth', $out);\r\n    \/\/ header('Content-Type:text\/xml');\r\n\r\n    $signedXML = '';\r\n    foreach ($out as $line) {\r\n        $signedXML = $signedXML.$line;\r\n    }\r\n\r\n    return $signedXML;\r\n}\r\n\r\n\/**\r\n    Funkcija skirta sugeneruoti u\u017eklausos XML skirt\u0105 duomen\u0173 pasi\u0117mimui\r\n    antrajai stadijai, kai vartotojas autentifikuojasi ir b\u016bna nukreipiamas\r\n    \u012f kitur.\r\n\r\n    @params:\r\n        String ticket;\r\n    @return:\r\n        String signedReqDataXML;\r\n*\/\r\nfunction generateDataReqXML($ticket) {\r\n    exec('\"C:\\Program Files\\Java\\jdk1.7.0_21\\bin\\java.exe\" -jar vaiisis.jar authdata '.$ticket, $out);\r\n    \/\/ header('Content-Type:text\/xml');\r\n\r\n    $signedXML = '';\r\n    foreach ($out as $line) {\r\n        $signedXML = $signedXML.$line;\r\n    }\r\n\r\n    \/\/ echo $signedXML; die();\r\n\r\n    return $signedXML;\r\n}\r\n\r\n?>\r\n<\/pre>\n<p><em>generateReqXML()<\/em> funkcija generuoja para\u0161\u0105 pirmam etapui kviesdama mano Jar&#8217;\u0105 su Java7u21 per <em>exec()<\/em>. \u017dinoma <em>exec()<\/em> n\u0117ra geras dalykas saugumo at\u017evilgiu, bet k\u0105 jau&#8230; :P<br \/>\n<em>generateDataReqXML($ticket)<\/em> funkcija atlieka t\u0105 pat\u012f, tik kad nurodomas yra bilietas. \u010cia antram etapui, generuoja para\u0161\u0105 gauti duomenims i\u0161 serviso.<\/p>\n<p>Pagrindinis failas <em>vaiisis_test.php<\/em>:<\/p>\n<pre lang=\"php\">\r\n<?php\r\n\/\/========= KONSTANTOS =========\r\n    $WEB_SERVISAS = \"https:\/\/www.epaslaugos.lt\/portal-test\/authenticationServices\/auth\";\r\n    $AUTHENTICATION_URL = \"https:\/\/www.epaslaugos.lt\/portal-test\/external\/services\/authentication\/v2\/\";\r\n    $SOAP_REQ = '<soapenv:Envelope xmlns:soapenv=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\" xmlns:aut=\"http:\/\/www.epaslaugos.lt\/services\/authentication\" xmlns:xd=\"http:\/\/www.w3.org\/2000\/09\/xmldsig#\">\r\n    <soapenv:Header\/>\r\n    <soapenv:Body>\r\n      %s\r\n    <\/soapenv:Body>\r\n    <\/soapenv:Envelope>';\r\n    $TICKET_REGEX = \"#<authentication:ticket>.+?<\/authentication:ticket>#\";\r\n\/\/==============================\r\n\/**\r\n  Funkcija skirta i\u0161traukti biliet\u0105 i\u0161 atsakymo nusiuntus atitinkam\u0105 u\u017eklaus\u0105.\r\n*\/\r\nfunction extractTicket($data) {\r\n    global $TICKET_REGEX;\r\n\r\n    preg_match($TICKET_REGEX, $data, $matches);\r\n    $rawTicket = $matches[0];\r\n    $rawTicket = str_replace(\"<authentication:ticket>\", \"\", $rawTicket);\r\n    $ticket = str_replace(\"<\/authentication:ticket>\", \"\", $rawTicket);\r\n    return $ticket;\r\n}\r\n\/\/==============================\r\n\/**\r\n  Funkcija skirta gra\u017eiai suformatuoti vard\u0105, pavard\u0119 bei gimimo dat\u0105 i\u0161 XML'o\r\n  kuris gaunamas paskutiniu etapu.\r\n*\/\r\nfunction formatName($rawXml) {\r\n    $rtnStr = '';\r\n    \r\n    \/\/sukuriam objekt\u0105 ir u\u017ekraunam dokument\u0105 paduot\u0105 per funkcijos argument\u0105\r\n    $domDoc = new DOMDocument();\r\n    $domDoc->loadXml($rawXml);\r\n\r\n    $nodeSet = $domDoc->getElementsByTagName('userInformation'); \/\/ gaunam visus blokus pagal \u0161it\u0105 tagname'\u0105 - vardas ir pavard\u0117\r\n    $vardas = $nodeSet->item(0)->getElementsByTagName('stringValue')->item(0)->nodeValue;\r\n    $pavarde = $nodeSet->item(1)->getElementsByTagName('stringValue')->item(0)->nodeValue;\r\n    $gimimoData = $nodeSet->item(2)->getElementsByTagName('dateValue')->item(0)->nodeValue;\r\n    $gimimoData = substr($gimimoData, 0, -1); \/\/ pa\u0161alinam Z raid\u0119 nuo galo\r\n\r\n    $nodeSet = $domDoc->getElementsByTagName('authenticationAttribute'); \/\/ gaunam asmens kodo blok\u0105\r\n    $asmensKodas = $nodeSet->item(0)->getElementsByTagName('value')->item(0)->nodeValue;\r\n\r\n    \/\/ gra\u017eiai suformatuojam i\u0161vedim\u0105\r\n    $rtnStr = 'Vardas: '.$vardas.'<br \/>Pavard\u0117: '.$pavarde.'<br \/>Gimimo data: '.$gimimoData.'<br \/>Asmens kodas: '.$asmensKodas;\r\n\r\n    return $rtnStr;\r\n}\r\n\/\/==============================\r\n\/**\r\n  Funkcija skirta pimam etapui, inicijuoti autentifikacij\u0105.\r\n  Gaunama $soap_req pilna SOAP'o u\u017eklausa, kuri\u0105 siun\u010diame\r\n  per POST'\u0105 \u012f $authentication_url i\u0161 kur gaunamas SOAP'o atsakymas\r\n  su ticket'u. I\u0161 \u010dia i\u0161traukiamas ticket'as ir siun\u010diamas \u012f $web_servisas\r\n  per GET'\u0105. Nusiuntus vartotojas b\u016bna nukreipiamas \u012f VAIISIS sistem\u0105.\r\n*\/\r\nfunction authenticate($soap_req, $web_servisas, $authentication_url) {\r\n  $contextData = array ('Connection' => 'Keep-Alive',\r\n                        'Accept-Encoding' => 'gzip,deflate',\r\n                        'Content-Type' => 'text\/xml;charset=UTF-8',\r\n                        'SOAPAction' => 'http:\/\/www.epaslaugos.lt\/services-test\/authenticationServiceProvider\/initAuthentication',\r\n                        'Content-Length' => strlen($soap_req),\r\n                        'Host' => 'www.epaslaugos.lt',\r\n                        'User-Agent' => 'Apache-HttpClient\/4.1.1 (java 1.5)');\r\n\r\n  $soap_do = curl_init();\r\n  curl_setopt($soap_do, CURLOPT_URL, $web_servisas);\r\n  curl_setopt($soap_do, CURLOPT_CONNECTTIMEOUT, 10);\r\n  curl_setopt($soap_do, CURLOPT_TIMEOUT, 10);\r\n  curl_setopt($soap_do, CURLOPT_RETURNTRANSFER, true);\r\n  curl_setopt($soap_do, CURLOPT_SSL_VERIFYPEER, false);\r\n  curl_setopt($soap_do, CURLOPT_SSL_VERIFYHOST, false);\r\n  curl_setopt($soap_do, CURLOPT_POST, true);\r\n  curl_setopt($soap_do, CURLOPT_POSTFIELDS, $soap_req);\r\n  curl_setopt($soap_do, CURLOPT_HTTPHEADER, $contextData);\r\n  $resp = curl_exec($soap_do);\r\n  $ticket = extractTicket($resp);\r\n  \/\/ echo 'Location: '.$authentication_url.'?ticket='.$ticket; die();\r\n  header('Location: '.$authentication_url.'?ticket='.$ticket);\r\n}\r\n\/\/==============================\r\n\/**\r\n  Funkcija skirta antram etapui, gauti vartotojo po autentifikacijos duomenis.\r\n  Gaunama $soap_req pilna SOAP'o u\u017eklausa, kuri\u0105 siun\u010diame\r\n  per POST'\u0105 \u012f $authentication_url i\u0161 kur gaunamas SOAP'o atsakymas\r\n  su vartotojo duomenimis ir vykdoma skriptas toliau.\r\n*\/\r\nfunction getUserData($soap_req, $web_servisas, $authentication_url) {\r\n  $contextData =  array ('Connection' => 'Keep-Alive',\r\n                        'Accept-Encoding' => 'gzip,deflate',\r\n                        'Content-Type' => 'text\/xml;charset=UTF-8',\r\n                        'SOAPAction' => 'https:\/\/www.epaslaugos.lt\/services-test\/authenticationServiceProvider\/getAuthenticationData',\r\n                        'Content-Length' => strlen($soap_req),\r\n                        'Host' => 'www.epaslaugos.lt',\r\n                        'User-Agent' => 'Apache-HttpClient\/4.1.1 (java 1.5)');\r\n\r\n  $soap_do = curl_init();\r\n  curl_setopt($soap_do, CURLOPT_URL, $web_servisas);\r\n  curl_setopt($soap_do, CURLOPT_CONNECTTIMEOUT, 10);\r\n  curl_setopt($soap_do, CURLOPT_TIMEOUT, 10);\r\n  curl_setopt($soap_do, CURLOPT_RETURNTRANSFER, true);\r\n  curl_setopt($soap_do, CURLOPT_SSL_VERIFYPEER, false);\r\n  curl_setopt($soap_do, CURLOPT_SSL_VERIFYHOST, false);\r\n  curl_setopt($soap_do, CURLOPT_POST, true);\r\n  curl_setopt($soap_do, CURLOPT_POSTFIELDS, $soap_req);\r\n  curl_setopt($soap_do, CURLOPT_HTTPHEADER, $contextData);\r\n  $resp = curl_exec($soap_do);\r\n  header('Content-Type:text\/xml');\r\n  echo $resp;\r\n}\r\n\/\/==============================\r\n\r\ninclude('generateSignatureJava.php');\r\nif (isset($_POST['ticket'])) {\r\n  $reqDataXml = sprintf($SOAP_REQ, generateDataReqXML($_POST['ticket']));\r\n  getUserData($reqDataXml, $WEB_SERVISAS, $AUTHENTICATION_URL);\r\n} else {\r\n  $reqXml = sprintf($SOAP_REQ, generateReqXML());\r\n  authenticate($reqXml, $WEB_SERVISAS, $AUTHENTICATION_URL);\r\n}\r\n\r\n?>\r\n<\/pre>\n<p>\u010cia jau yra \u012f k\u0105 \u017ei\u016br\u0117ti.<\/p>\n<p><em>$SOAP_REQ<\/em> konstanta nustato tai \u012f k\u0105 reikia sud\u0117ti gaut\u0105 para\u0161\u0105 kad b\u016bt\u0173 paruo\u0161ta siuntimui, dedama tarp <em><soapenv:Body><\/em> tag&#8217;o.<\/p>\n<p><em>extractTicket($data)<\/em> i\u0161traukia biliet\u0105 su regex i\u0161 atsakymo XML&#8217;e.<\/p>\n<p><em>formatName($rawXml)<\/em> suformatuoja i\u0161vest\u012f i\u0161 atsakymo. Testavimo sumetimais tiesiog gra\u017eiai para\u0161o vard\u0105, pavard\u0119, gimimo dat\u0105 ir asmens kod\u0105. <strong>Beje<\/strong> gimimo data gaunama su Z (galb\u016bt ir kitokia) raide ant galo ka\u017ekod\u0117l, tad j\u0105 reikia pa\u0161alinti.<\/p>\n<p><em>authenticate($soap_req, $web_servisas, $authentication_url)<\/em> funkcija pirmam etapui, inicijuoja autentifikacij\u0105. \u0160itoje funkcijoje u\u017eklausos header&#8217;yje turi b\u016bti nustatoma SOAPAction interfeisas. Kadangi siun\u010diama visais atvejais ten pat, tai SOAPAction nurodo kok\u012f interfeis\u0105 naudoti serveriui, tai nurodoma yra:<br \/>\n<code>'SOAPAction' => 'http:\/\/www.epaslaugos.lt\/services-test\/authenticationServiceProvider\/initAuthentication'<\/code><br \/>\nNaudojant normaliai, -test dalis turi b\u016bti pa\u0161alinta, o daugiau tai standartinis siuntimas su CURL&#8217;u. Toje pa\u010dioje vietoje <code>$ticket = extractTicket($resp);<\/code> i\u0161traukiamas bilietas i\u0161 atsakymo ir <code>header('Location: '.$authentication_url.'?ticket='.$ticket);<\/code> nuvaro vartotoj\u0105 autentifikuotis.<\/p>\n<p><em>getUserData($soap_req, $web_servisas, $authentication_url)<\/em> tiesiog gauna visus duomenis kuri\u0173 mums reikia ir juos atvaizduoja. \u010cia jau header&#8217;yje turi nusirodyti:<br \/>\n<code>'SOAPAction' => 'https:\/\/www.epaslaugos.lt\/services-test\/authenticationServiceProvider\/getAuthenticationData'<\/code><\/p>\n<p>Ir paskutin\u0117 dalis (eilut\u0117s 116-122) atlieka logik\u0105 koki\u0105 funkcij\u0105 kada vykdyti, kadangi a\u0161 <em>postBackURL()<\/em> esu nusistat\u0119s t\u0105 pat\u012f puslap\u012f, tai vartotoj\u0105 gra\u017eina ten pat i\u0161 kur i\u0161\u0117jo. Kad aptikti kada vartotojas ateina jau po autentifikacijos, galima tikrinti ar <em>$_POST[&#8216;ticket&#8217;]<\/em> yra u\u017estatytas &#8211; jei ne, tuomet at\u0117jo pirm\u0105 kart\u0105.<\/p>\n<p>Tiek to viso kodo. Trumpiau kas apskritai vyksta tai tiesiog:<\/p>\n<ol>\n<li>Vartotojas ateina \u012f m\u016bs\u0173 puslap\u012f<\/li>\n<li>Sugeneruojama ir siun\u010diama u\u017eklausa<\/li>\n<li>Serveriui patikrinus, jeigu viskas atitinka, gaunamas bilietas<\/li>\n<li>Bilietas siun\u010diamas per GET&#8217;\u0105 \u012f server\u012f kartu nukreipiant vartotoj\u0105<\/li>\n<li>Vartotojas atlieka proced\u016br\u0105 ir paspaud\u017eia &#8220;Patvirtinti&#8221; vald\u017eios vartuose<\/li>\n<li>Vartotojui patvirtinus jis nukreipiamas \u012f <em>postBackURL()<\/em> kartu su bilietu per POST&#8217;\u0105, tuo pa\u010diu kuris buvo gautas pirm\u0105 kart\u0105<\/li>\n<li>Gaut\u0105 biliet\u0105 \u012fki\u0161ame \u012f u\u017eklausos XML&#8217;\u0105 ir siun\u010diame \u012f server\u012f<\/li>\n<li>Jeigu galutinis bilieto patvirtinimas serveryje sutampa, gaunamas XML&#8217;o atsakymas kuriame yra visi reikalingi duomenys. Jeigu patvirtinti nepavyko (bilieto galiojimas baig\u0117si arba jis ne validus) tada gaunama atitinkamas klaidos prane\u0161imas<\/li>\n<\/ol>\n<p>Tai va tiek to panaudojimo. N\u0117ra labai sud\u0117tinga kai supranti kas, kada, kur ir kaip turi b\u016bti siun\u010diama. Jeigu stojasi kokie nors klausimai, ra\u0161ykite \u012f komentarus, bandysiu atsakyti :)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sveiki :) \u0160\u012f kart\u0105 nor\u0117\u010diau apra\u0161yti apie fain\u0105 dalyk\u0117l\u012f i\u0161 VIISP (elektroniniai vald\u017eios vartai, anks\u010diau<\/p>\n","protected":false},"author":2,"featured_media":2237,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,5],"tags":[902,903,901,900,899],"class_list":["post-2234","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ltu","category-my-tutos","tag-paslauga","tag-tapatybe","tag-tapatybes-nustatymas","tag-vaiisis","tag-viisp"],"_links":{"self":[{"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/posts\/2234","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/comments?post=2234"}],"version-history":[{"count":0,"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/posts\/2234\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/media\/2237"}],"wp:attachment":[{"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/media?parent=2234"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/categories?post=2234"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/9v.lt\/blog\/wp-json\/wp\/v2\/tags?post=2234"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}