I woudlike to execute GET request :
HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION);
URIBuilder uriBuilder = new URIBuilder(request.getURI())
.addParameter("code", "001")
.addParameter("name", "AAA")
String auth = user + ":" + mdp;
byte[] encodedAuth = Base64.encodeBase64(
auth.getBytes(StandardCharsets.ISO_8859_1));
String authHeader = "Basic " + new String(encodedAuth);
request.setHeader(HttpHeaders.AUTHORIZATION, authHeader);
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute((HttpUriRequest) uriBuilder);
int statusCode = response.getStatusLine().getStatusCode();
When I try to catch my HTTPResponse client.execute((HttpUriRequest) uriBuilder);
I have this error :
java.lang.ClassCastException: class org.apache.http.client.utils.URIBuilder cannot be cast to class org.apache.http.client.methods.HttpUriRequest (org.apache.http.client.utils.URIBuilder and org.apache.http.client.methods.HttpUriRequest are in unnamed module of loader 'app')
You are facing the error because you are trying to cast an instance of URIBuilder to HttpUriRequest.
You need to create an appropriate HttpUriRequest implementation in order to execute your HTTP request.
In your use case I suppose it should looks like this:
URIBuilder uriBuilder = new URIBuilder(URL_SECURED_BY_BASIC_AUTHENTICATION)
.addParameter("code", "001")
.addParameter("name", "AAA");
URI uri = uriBuilder.build();
HttpGet request = new HttpGet(uri);
String auth = user + ":" + mdp;
byte[] encodedAuth = Base64.encodeBase64(
auth.getBytes(StandardCharsets.ISO_8859_1));
String authHeader = "Basic " + new String(encodedAuth);
request.setHeader(HttpHeaders.AUTHORIZATION, authHeader);
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
It seems for your comment that you are trying to connect to a site using SSL: the problem is that your Java code does not trust the server.
You need to configure a valid certificate chain and instruct your code to use it in order to solve the problem.
Apache Client does not rely on the standard JSSE mechanism for this purpose. Instead, you need to configure a SSLContext with an appropriate TrustManager. Please, see the following code (the first part is derived from this extraordinary documentation fragment in the Android developer site):
// Load your server certificate
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream input = new BufferedInputStream(
new FileInputStream("server.crt")
);
Certificate certificate;
try {
certificate = cf.generateCertificate(input);
} finally {
input.close();
}
// Create an in-memory KeyStore containing the server certificate
// It is required in order to configure the TrustManager
String keyStoreType = KeyStore.getDefaultType(); // JKS
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("cert", certificate);
// Create a TrustManager that trusts the server certificates in the KeyStore
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()
);
trustManagerFactory.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustManagerFactory.getTrustManagers(), null);
// Now, the actual Apache Client part
//Create a SSLConnectionSocketFactory and pass it the above created SSLContext
SSLConnectionSocketFactory factory =
new SSLConnectionSocketFactory(sslcontext, new NoopHostnameVerifier()
);
//Create the actual HttpClient
CloseableHttpClient client = HttpClients
.custom()
.setSSLSocketFactory(factory)
.build()
;
// Use this client to perform your HTTP invocation
HttpResponse response = client.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
You can obtain the server certificate from your browser or with tools like openssl. Please, see this great SO question.
Related
I'm using the Apache HTTP client (version 4.5.13) in Java 8 to perform a POST call that requires the client to authenticate using a certificate certificate, that I have stored in a .PFX file.
This is the code I'm using:
public static void performClientRequest() throws Exception {
//Trust Strategy to accept any server certificate
TrustStrategy trustStrategy = new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
};
//Load PFX client certificate
KeyStore clientStore = KeyStore.getInstance("PKCS12");
InputStream instream = new FileInputStream("C:\\client.pfx");
try {
clientStore.load(instream, null);
} finally {
instream.close();
}
//Create ssl context with key store and trust strategy
SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(clientStore, null)
.loadTrustMaterial(trustStrategy)
.build();
//Create ssl socket factory from context
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
//Create HTTP client
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(sslSocketFactory)
.build();
//Perform call
URI url = new URI("https://mysite.foo");
HttpPost request = new HttpPost(url);
request.setHeader("Content-Type","application/json");
request.setHeader("Accept", "application/json");
String body = "...";
StringEntity bodyEntity = new StringEntity(body);
request.setEntity(bodyEntity);
HttpResponse response = httpClient.execute(request);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
EntityUtils.consume(entity);
}
I've used this code in in the past and it worked perfectly back then, but now I'm trying to reuse it and it just doesn't send the certificate, the server replies with:
HTTP/1.1 403 No client certificate supplied
How can I debug this and discover why the certificate is not being sent?
Note: I implemented a similar call both in C# and using Postman, and in both cases it works perfectly, so the client certificate authentication to the server is working, it's just not working in my Java implementation.
So, I don't know if this is a bug or intended behavior (if so, why?), but apparently the PFX file must be password-protected, then it gets sent correctly. I could not make this work with a non-protected PFX file and passing null as the password like I was doing in the code I posted in the question.
So the problem is solved, but I would be curious if anyone could comment on WHY this happens.
This is the exception that I'm having
Host name 'bla bla bla.com' does not match the certificate subject provided by the peer (CN=*.bla bla bla.com, OU=PositiveSSL Wildcard, OU=Domain Control Validated)
I already saw this question:
Ignoring SSL certificate in Apache HttpClient 4.3
and I did as it suggests, but it didn't work. I have seen many question related to the problem but they are all deprecated.
This is my code:
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf =
new SSLConnectionSocketFactory(builder.build());
CloseableHttpClient httpclient =
HttpClients.custom().setSSLSocketFactory(sslsf).build();
HttpGet httpGet = new HttpGet("https://b.blablabla.com");
CloseableHttpResponse response1 = httpclient.execute(httpGet);
try {
System.out.println(response1.getStatusLine());
HttpEntity entity1 = response1.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity1);
} finally {
response1.close();
}
How can I bypass this certificate thing? This is just for testing; it is not a real production environment.
Beside localhost you can add own custom hostnames to your development-machine. Use the C:/windows/system32/etc/hosts to add the hostname anjadavid.blablabla.com in example.
Now open your browser and go to https://anjadavid.blablabla.com and the error disappears.
i want to do a HTTP POST request, which is secured by ssl.
the client is my java program, which is posting to a https-url (https:// ...). the certificate of the website is verified, i am using Apache HttpClient 4.5.1
with a normal post-request and a custom httpclient.
HttpContext context = HttpClientContext.create();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setDefaultMaxPerRoute(MAX_CONNECTIONS_PER_ROUTE);
cm.setMaxTotal(MAX_TOTAL_CONNECTIONS);
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(cm)
.build();
HttpContext context = HttpClientContext.create();
HttpPost login = new HttpPost("https://example.org"); // example url
login.addHeader("Content-Type", "application/json; charset=UTF-8");
login.addHeader("Accept", "application/json; charset=UTF-
login.setEntity(new StringEntity(loginData, ContentType.create("application/json", "UTF-8")));
JSONResponseHandler<JSONObject> rh = new JSONResponseHandler<>();
JSONObject test = client.execute(login, rh, context);
is this sufficend to get a ssl-secured connection or do i have to work with KeyStore, SSLContext and SSLConnectionFactory?
if i have to use those, how would i do this in an efficent way. i only saw examples how to allow self-signed certificates.
I have a url where a file is available for download via http. If I hit that url with a curl the file downloads without issues. But if I try in code with Apache HttpClient, it gives an exception. Here is the code...
HttpClient httpClient = new HttpClient()
HttpMethod method = new GetMethod("https://www2.mycompany.com/internet/cats/productfeed.nsf/xmlproductfeed?openview")
def responseCode = httpClient.executeMethod(method)
The exception is
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:882)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1188)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:654)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:100)
at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
Could it be the https or the www2 in the url?
You are calling the URL through HTTPS, this is a TLS connection. You need to set up your client to use SSL/TLS.
Here is an example, rewrite to HttpGet, but this should be easy:
// Trust own CA and all self-signed certs
SSLContext sslcontext = createEasySSLContext();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,
new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" }, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
String userCredentials = username + ":" + password;
String basicAuth = "Basic " + new String(new Base64().encode(userCredentials.getBytes()));
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
HttpClientContext localContext = HttpClientContext.create();
localContext.setCredentialsProvider(credentialsProvider);
HttpPost httpPost = new HttpPost(path);
I am trying to post a SharePoint list item to a SharePoint 2010 list using Java client.
I am able to read the SP list items using below code but I am not sure how to write to the SharePoint.
For the post operation, I am getting http 401 error.
Any guidance will be greatly appreciated.
GET Operation:
String url = "https://organization.company.com/sites/Ateam/_vti_bin/ListData.svc/TableLoadInfo"; DefaultHttpClient client = new DefaultHttpClient();
NTCredentials credentials = new NTCredentials(username, password, hostname, domain);
AuthScope scope = new AuthScope(hostname, 443);
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[] { trustmanager }, null);
SSLSocketFactory sf = new SSLSocketFactory(sslcontext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme https = new Scheme("https", 443, sf);
client.getConnectionManager().getSchemeRegistry().register(https);
client.getCredentialsProvider().setCredentials(scope, credentials);
HttpGet request = new HttpGet(url);
//request.addHeader("Accept", "application/xml");
request.addHeader("Accept", "application/json;odata=verbose");
HttpResponse response = client.execute(request);
POST Operation:
String url = "https://organization.company.com/sites/Ateam/_vti_bin/ListData.svc/TableLoadInfo";
DefaultHttpClient client = new DefaultHttpClient();
NTCredentials credentials = new NTCredentials(username, password, hostname, domain);
AuthScope scope = new AuthScope(hostname, 443);
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[] { trustmanager }, null);
SSLSocketFactory sf = new SSLSocketFactory(sslcontext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme https = new Scheme("https", 443, sf);
client.getConnectionManager().getSchemeRegistry().register(https);
client.getCredentialsProvider().setCredentials(scope, credentials);
// POST a data
HttpPost request = new HttpPost(url);
request.addHeader("Accept", "application/json;odata=verbose");
request.addHeader("Content-type", "application/json;odata=verbose");
// request.addHeader("X-RequestDigest", FormDigestValue);
request.addHeader("X-HTTP-Method", "POST");
request.addHeader("If-Match", "*");
JSONStringer json = (JSONStringer) new JSONStringer().object().key("Table_Name").value("TableName 1")
.key("Load_Frequency").value("Weekly").key("Cycle").value("CURRENT").endObject();
StringEntity se = new StringEntity(json.toString());
request.setEntity(se);
HttpResponse response = client.execute(request);
When you post data to SharePoint you have to add "FormDigestValue" inside the header.
Please Note you have commented the line "request.addHeader("X-RequestDigest", FormDigestValue);".
That is the reason you get 401 Error.
First you have to get the "FormDigestValue" value form your current site.
Then add that value inside the header.
Following Code shows the way to get the FormDigestValue.
String digestqueryURL = serverurl + subsite + "/" + "_api/contextinfo";
HttpPost httpPost = new HttpPost(digestquery);
httpPost.addHeader("Accept", "application/json;odata=verbose");
httpPost.addHeader("X-ClientService-ClientTag", "SDK-JAVA");
HttpResponse response = httpClient.execute(httpPost);
byte[] content = EntityUtils.toByteArray(response.getEntity());
String jsonString = new String(content, "UTF-8");
JSONObject json = new JSONObject(jsonString);
String FormDigestValue = json.getJSONObject("d")
.getJSONObject("GetContextWebInformation")
.getString("FormDigestValue");
Then add the FormDigestValue to the header when you do the post operations.
request.addHeader("X-RequestDigest", FormDigestValue);