I have a certificate file AUTH_RSA256_8827cdaa76b01019066fbe4d914d67a0e31677bc.p12 and a password issued by the administrator of the service server. How java authorize for further parsing. The purpose of the program to connect, provide a certificate, then on the authorization page to your personal account there are 2 RadioButton a) and b) and a field for entering a password (which is the same as the password of the key), select b) and enter the password, (pass internal authorization), then, using jsoup, see the new rows of the table and bring me a message about the new rows. Constantly looking at the browser and clicking "update" is not difficult, but very inconvenient ...

With the help of the code (and consultations) I was only able to access (erroneously) and parse the page in which you need to provide a certificate in which there is a button "Select key"

 <input class="btn btn-primary" name="selectP12File" id="selectP12File" value="Выберите ключ" onclick="selectP12File()" type="button"> 

Here is the code itself:

  KeyStore clientStore = KeyStore.getInstance("PKCS12"); clientStore.load(new FileInputStream("C:\\AUTH_RSA256_8827cdaa76b01019066fbe4d914d67a0e31677bc.p12"), "mypassword".toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(clientStore, "mypassword".toCharArray()); KeyManager[] kms = kmf.getKeyManagers(); KeyStore trustStore = KeyStore.getInstance("JKS"); trustStore.load(new FileInputStream("C:\\Program Files\\Java\\jre-9.0.4\\lib\\security\\cacerts"), "changeit".toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); TrustManager[] tms = tmf.getTrustManagers(); SSLContext sslContext = null; sslContext = SSLContext.getInstance("TLS"); sslContext.init(kms, tms, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); URL url = new URL("https://server/ru/user/login"); HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection(); if (urlConn != null) { System.out.println(); System.out.println("****** Content of the URL ********"); BufferedReader br = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); String input; while ((input = br.readLine()) != null){ System.out.println(input); } br.close(); } else { System.out.println("not connect"); } urlConn.disconnect(); 

Previously a server certificate was added to the cacerts and keytool commands.

Please share your experience. I will be glad to constructive criticism and your opinion of what I am doing wrong. Thank you for attention!

  • Try it here: stackoverflow.com/a/7016969/3212712 - Yuriy SPb
  • @YuriySPb I found this solution, and tried to implement it, and an error occurs in this section of the code - p_redator
  • What error and in what part of the code? - Yuriy SPb
  • KeyStore trustStore = KeyStore.getInstance ("JKS"); trustStore.load (new FileInputStream ("cacerts"), "mypasswod" .toCharArray ()); The error that does not find the file "cacerts" is completely unclear why these lines and what role they play. in theory, I also have a p12 file. Which through the browser works without problems ... If instead of "cacerts" insert "my-path. P12" then another error is continued ... - p_redator
  • Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: sep

1 answer 1

Your answer from the English version is correct. However, here it is necessary to insert some clarifications. There is a client and server signatures. I dare to assume that the administrator has given you a certificate and a key (!) In the .p12 storage for client signature. Here is an example of creating a client request signature:

 KeyStore clientStore = KeyStore.getInstance("PKCS12"); clientStore.load(new FileInputStream("C:\\AUTH_RSA256_8827cdaa76b01019066fbe4d914d67a0e31677bc.p12"), "mypasswod".toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(clientStore, "mypassword".toCharArray()); KeyManager[] kms = kmf.getKeyManagers(); SSLContext sslContext = SSLContext.getInstance("TLS"); //обратите внимание на второй параметр, т.е. мы доверяем списку сертификатов по умолчанию sslContext.init(kms, null, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); URL url = new URL("https://server/ru/user/login"); HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection(); if (urlConn != null) { System.out.println("****** Content of the URL ********"); BufferedReader br = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); String input; while ((input = br.readLine()) != null){ System.out.println(input); } br.close(); } else { System.out.println("not connect"); } urlConn.disconnect(); 

But. Given your unusual URL with https https://server/ru/user/login (the domain is not public, so most likely it is signed with a self-signed certificate) you will most likely have to do some manipulations with the list of trusted certificates (list of server signatures that we trust ). This: either add the certificate of this domain to the default trust store , or create your own trust store with the required certificate inside and specify it when creating the connection.

In the link you specified, it was the second option that was used.

 KeyStore trustStore = KeyStore.getInstance("JKS"); trustStore.load(new FileInputStream("cacerts"), "changeit".toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); TrustManager[] tms = tmf.getTrustManagers(); 

However, it was not explicitly stated that this storage should still be created, because you had an error that it does not find the file "cacerts". But I will show the first option. First you need to steal the certificate from your site https://server/ru/user/login . To do this, open it in a browser, click to the left of the domain on the lock -> view certificate -> Details tab -> export. Note that the CN field in the certificate must match the domain. Here is a picture with an example:

Example

The default certificate %JRE_HOME%/lib/security/cacerts is located at %JRE_HOME%/lib/security/cacerts , where %JRE_HOME% is the path to the JRE. You can add another certificate to it using the keytool.exe utility built into the JRE ( %JRE_HOME%/bin/keytool.exe ) with the following command:

 %JRE_HOME%/bin/keytool.exe -importcert -file 'path/myTrustCert.cer' -alias 'myTrustCert' -keystore `%JRE_HOME%/lib/security/cacerts` -storepass 'changeit' 

, where -file 'path/myTrustCert.cer' is the certificate (preferably the full path) that we took earlier from the site, -storepass 'changeit' is the default password for the default storage, -alias 'myTrustCert' is an alias for the new certificate (does not play a special role, the main thing is that it does not overlap with other certificates in this store).

After that your program should earn, if of course my guess is correct.

  • Thank you for a very detailed explanation, Temka, too, you are absolutely right, everything went great, but please generously forgive, I saw the content of the site in which I saw familiar lines, <input class = "btn btn-primary" name = "selectP12File" id = "selectP12File" value = "Select the key" onclick = "selectP12File ()" type = "button"> Now, if I understand correctly, I have to send the key + password. How can the site send it again? - p_redator
  • Those. I put a page into which I enter, click "Select a key", enter the password, and get access to the desired table - p_redator
  • @p_redator First of all, answer the main question. Does the server require signing a request at the level of ssl (client signature)? Or does he require sending the key that the administrator gave you, using an HTML form (which is generally contrary to sound logic)? It’s also not clear from the comments above which site content you mean. - Temka, too,
  • I will try to sort everything out. The general login script is as follows. 1) we pass to the address https://server/ru/user/login and the browser (chrome) displays a window with a selection of the certificate that was loaded earlier (the one specified in the C code: \\ AUTH_RSA256_) 2) displays a window with the selection the window of one of the two RadioButton ( a) or b) ) and enter the password exactly the same as from the certificate (feeling that there is a double authorization, first by key, further by password), after passing it I get to the page https://server/ru/searchanno where I search for the information I need, which I would like to receive - p_redator
  • Then I thought to generate such a line that the browser gave me https://server/ru/searchanno?binname=&numberAnno=&titleAnno=®ion_supply=11&plan_amoun_start=&plan_amoun_end=&methodz=0&statuses=0&date_start=&date_end=&subj_type=0 to parse her - p_redator