Supporting communication with servers who has a self-signed certificate
已回答
Hi,
My plugin communicates with some servers (configured by the users) who use self-signed certificates. How can I enable them to communicate with those servers over https? Important to say that those would be development servers and information passing won't be sensitive.
I tried adding the certificate to the Pycharm (Tools -> server certificates) and also checking the "Accept non-trusted certificates automatically" but that didn't help.
The code I use for making the requests:
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
public class RESTClient {
public String executeHttpRequest(CloseableHttpClient httpClient, HttpUriRequest request) {
try {
CloseableHttpResponse response = httpClient.execute(request);
try {
HttpEntity resEntity = response.getEntity();
Integer statusCode = response.getStatusLine().getStatusCode();
if (statusCode.equals(200)) {
return EntityUtils.toString(resEntity, StandardCharsets.UTF_8);
} else if (statusCode.equals(403)) {
LOG.info("Encountered error while sending a request to ,\nplease check your API key. Status code 403 - Forbidden");
} else if (statusCode.equals(400)) {
LOG.info("Encountered error while sending a request. Status code 400");
} else if (resEntity != null) {
LOG.error("Encountered error while sending a request to . Status code " + statusCode.toString());
}
EntityUtils.consume(resEntity);
} finally {
response.close();
}
} catch (HttpHostConnectException e) {
LOG.info("Encountered error while sending a request to , error message was: " + e.getMessage());
} catch (ClientProtocolException e) {
LOG.info("Encountered error while sending a request to , error message was: " + e.getMessage());
} catch (IOException e2) {
LOG.info("Encountered error while sending a request to , error message was: " + e2.getMessage());
}
return "";
}
public String sendPostRequest(String serverUrl, String apiKey, String params, String endpointPath, String filePath) {
CloseableHttpClient httpClient = getHttpClient();
try {
String dest = serverUrl + endpointPath;
HttpPost httppost = new HttpPost(dest);
httppost.setHeader("Authorization", apiKey);
httppost.addHeader("Accept", "application/json");
if (stringIsNotEmptyOrNull(filePath)) {
LOG.info("Sending POST request. File path is: " + params);
FileBody bin = new FileBody(new File(filePath));
httppost.setEntity(MultipartEntityBuilder.create()
.addPart("file", bin)
.build());
} else {
LOG.info("Sending POST request. Params are: " + params);
httppost.addHeader("content-type", "application/json");
httppost.setEntity(new StringEntity(params));
}
return executeHttpRequest(httpClient, httppost);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
LOG.error("Encountered UnsupportedEncodingException while making request to , error message was: " + e.getMessage());
} finally {
try {
httpClient.close();
} catch (IOException e1) {
LOG.error("Encountered error while closing connection with , error message was: " + e1.getMessage());
}
}
return "";
}
public String sendGetRequest(String serverUrl, String apiKey, String params, String endpointPath) {
CloseableHttpClient httpClient = getHttpClient();
try {
String dest = serverUrl + endpointPath;
HttpGet httpGet = new HttpGet(dest);
httpGet.setHeader("Authorization", apiKey);
httpGet.addHeader("Accept", "application/json");
return executeHttpRequest(httpClient, httpGet);
} finally {
try {
httpClient.close();
} catch (IOException e1) {
LOG.error("Encountered error while closing connection, error message was: " + e1.getMessage());
}
}
}
public CloseableHttpClient getHttpClient() {
CloseableHttpClient httpClient = HttpClients.createDefault();;
return httpClient;
}
}
请先登录再写评论。
If you use builtin com.intellij.util.io.HttpRequests, certificates defined in IDE will be taken into account automatically.
Hi Yann,
Thank you for the quick response. I'm checking that API, how can I add a JSON body to a POST request there?
HttpClient4 example for what I want to do:
```
publicvoidwhenPostJsonUsingHttpClient_thenCorrect()throwsClientProtocolException, IOException {CloseableHttpClient client = HttpClients.createDefault();HttpPost httpPost =newHttpPost("http://www.example.com");String json ="{"id":1,"name":"John"}";StringEntity entity =newStringEntity(json);httpPost.setEntity(entity);CloseableHttpResponse response = client.execute(httpPost);assertThat(response.getStatusLine().getStatusCode(), equalTo(200));client.close();}```Something along this pattern:
HttpRequests.post(url, "application/json")...connect( r -> r.write(jsonString) )
Hi Yann,
I still get an SSL error when using your library. This happens both when I upload the certificate to Pycharm or check the "Allow any certificate"
My code:
Can anyone assist with this, please? It is of high importance for us and would be really appreciated
Hi there,
Actually you can use any HTTP library you prefer but you need to set the SSL context in use to
according to their API.
For instance, in case of Apache HttpClient 4.x it means constructing an HttpClient instance with a builder:
Also, according to the given stacktrace the error happens on hostname validation step that we don't intercept at the moment. Most likely it indicates some problem with the certificate you use.
If you're sure that everything is ok or don't have control other this certificate, you can still fallback to:
in this specific HttpClient builder to skip this step altogether.
Mikhail, thank you for your answer, I will try it. How can I use the proxy that the user defines in PyCharm?
com.intellij.util.proxy.CommonProxy, see usage in com.intellij.util.net.HttpConfigurable#openConnection
You can propagate all the proxy configuration from IDE settings to an HttpClient instance with: