I have been able to successfully authentication to a service that requires ntlm authentication when using the WinHttpClients and a GET request. However when I try to do a POST I always get a 401 return code. Has anyone done this sucessfully before?
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
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.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.WinHttpClients;
public class WindowsAuthPOst {
public static void main (String []args) throws Exception, IOException
{
org.apache.log4j.BasicConfigurator.configure();
CloseableHttpClient httpclient = WinHttpClients.createDefault();
HttpHost target = new HttpHost("SomeHost.domain", 443, "https");
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet("/some/Service.svc");
CloseableHttpResponse response1 = httpclient.execute(target, httpget, context);
try {
HttpEntity entity1 = response1.getEntity();
} finally {
response1.close();
}
// Execute an expensive method next reusing the same context (and connection)
HttpPost httppost = new HttpPost("/some/Service.svc");
httppost.setHeader("SOAPAction", "Some Soap Action");
httppost.setEntity(new StringEntity("Soap Payload"));
CloseableHttpResponse response2 = httpclient.execute(target, httppost, context);
try {
HttpEntity entity2 = response2.getEntity();
} finally {
response2.close();
}
}
}
You can check if it is available with.
if (!WinHttpClients.isWinAuthAvailable()) {
System.out.println("Integrated Win auth is not supported!!!");
}
If not, it could be that you do not have jna.jar in your classpath. It depends on jna and will silently return false on the above if it not there, see source code.
Try with get (or options) before post. Some webservers requires that because of CORS.
https://stackoverflow.com/a/38410411/2376661
Related
When making a post request to my backend, I get the following error. I can't really find a fix online and am very new to Java.
Here is the error:
Caused by: java.lang.ClassNotFoundException: org.apache.http.concurrent.Cancellable
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 59 more
Code
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
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.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.http.HttpHeaders;
import java.util.ArrayList;
import java.util.List;
public class APIBridge {
private final CloseableHttpClient httpClient = HttpClients.createDefault();
public String url = "http://localhost:9004/index.php";
public static void Register(String username, String password) throws UnsupportedEncodingException {
String url = "http://localhost:9004/index.php";
HttpPost post = new HttpPost(url);
// Add request parameter, form parameters
List<NameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("username", username));
urlParameters.add(new BasicNameValuePair("password", password));
urlParameters.add(new BasicNameValuePair("Register", "true"));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post)) {
System.out.println(EntityUtils.toString(response.getEntity()));
} catch (ClientProtocolException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void close() throws IOException {
httpClient.close();
}
private void sendGet() throws Exception {
HttpGet request = new HttpGet("https://www.google.com/search?q=mkyong");
// Add request headers
request.addHeader("custom-key", "mkyong");
//request.addHeader(, "Googlebot");
try (CloseableHttpResponse response = httpClient.execute(request)) {
// Get HttpResponse Status
System.out.println(response.getStatusLine().toString());
HttpEntity entity = response.getEntity();
Header headers = entity.getContentType();
System.out.println(headers);
if (entity != null) {
// Return it as a String
String result = EntityUtils.toString(entity);
System.out.println(result);
}
}
}
IMO, it is easier to use the HTTP client in the JDK, so I have provided an answer demonstrating this alternate approach.
The Apache HTTP libraries were never targeted at somebody who is "new to Java". If you use them, make sure you use the correct versions of all the libraries and matching documentation as the library has gone through multiple incompatible API changes over years of library upgrades.
From your question, your module-info.java may be wrong or may need to be deleted. But your issue could also be caused by an environment setup or dependency version issue.
Basically, the class isn’t on the class or module path. Or it is on a path, but it is not accessible. The reason for that is not discernable from your question.
Example JavaFXApp using JDK HTTP Client
Makes a post request, gets the result as text and places the text in a TextArea.
module-info.java
module com.example.httpapp {
requires javafx.controls;
requires java.net.http;
exports com.example.httpapp;
}
src/main/java/com/example/httpapp/HttpApp.java
package com.example.httpapp;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class HttpApp extends Application {
#Override
public void start(Stage stage) throws IOException, URISyntaxException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://jsonplaceholder.typicode.com/posts"))
.POST(HttpRequest.BodyPublishers.ofString("Sample Post Request"))
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
String responseBody = response.body();
TextArea textArea = new TextArea(responseBody);
textArea.setStyle("-fx-font-family: monospace;");
stage.setScene(new Scene(textArea));
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Authentication
Outside of a local test app, you should not send unencrypted authentication data over a network connection as you have in your question code.
If you also need authentication, it is best to communicate over HTTPS. Then you can securely use basic or digest authentication, or HTTPS mutual authentication, or encode the authentication information in the post body.
Examples for basic authentication using the Java HTTP client are at:
Baeldung: Java HttpClient Basic Authentication
I have to connect to a URL, and in that i have a link click here to download, when i click on it,it downloads a zip file which has multiple files in it. My requirement is to download that zip file using java application.I am trying to point to a URl and download the file.
I have taken the code from How to remotely login to a Jenkins server using Java?
Below is the code:
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URI;
public class JenkinsScraper {
public String scrape(String urlString, String username, String password) throws ClientProtocolException, IOException {
URI uri = URI.create(urlString);
HttpHost host = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(uri.getHost(), uri.getPort()), new UsernamePasswordCredentials(username, password));
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(host, basicAuth);
CloseableHttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
HttpGet httpGet = new HttpGet(uri);
// Add AuthCache to the execution context
HttpClientContext localContext = HttpClientContext.create();
localContext.setAuthCache(authCache);
HttpResponse response = httpClient.execute(host, httpGet, localContext);
return EntityUtils.toString(response.getEntity());
}
public static void main(String args[]) throws IOException {
JenkinsScraper obj = new JenkinsScraper();
String result = obj.scrape("https://info-build.gm.com/view/tools/job/MISC.DefectSummaryReport/lastSuccessfulBuild/artifact/","JZYH8B","may#2017");
System.out.print("result :: " + result);
}
}
I'm facing below exception:
Exception in thread "main" java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Base64.<init>(I)V
at org.apache.http.impl.auth.BasicScheme.authenticate(BasicScheme.java:168)
Had someone worked on this type of requirement where we will have a link in the Jenkins URL, using java code we need to hit the URL and download the zip file.Do i need tp use any other API to achieve this functionality.Any suggestions would be helpful.
I have been trying to connect to CRM using the below Java code, but I am getting an authentication issue.
package com.raj;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
public class MSDynaOData {
/**
* #param args
*/
public static void main(String[] args) throws ClientProtocolException, IOException {
DefaultHttpClient httpclient = new DefaultHttpClient();
NTCredentials creds = new NTCredentials("XXXXXXXXXX", "XXXXXXX", "", "");
httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
HttpHost target = new HttpHost("XXXXXXXXX", 80, "http");
HttpContext localContext = new BasicHttpContext();
// Execute a cheap method first. This will trigger NTLM authentication
String url = "/XRMServices/2011/Organization.svc/Account";
url += "?$select=Name";
HttpGet httpget = new HttpGet(url);
httpget.addHeader("Accept", "application/json");
HttpResponse response = httpclient.execute(target, httpget, localContext);
HttpEntity entity = response.getEntity();
System.out.println(" Status :: " + response.getStatusLine());
for (Header header : response.getAllHeaders()) {
System.out.println(header.getName() + " : " + header.getValue());
}
System.out.println(IOUtils.toString(entity.getContent()));
}
}
Response contains :
Constants.TokenizedStringMsgs.GENERIC_ERROR = "<H1>Sorry, but we're having trouble signing you in</H1><p>Please try again in a few minutes. If this doesn't work, you might want to contact your admin and report the following error: #~#ErrorCode#~#.</p>";
Constants.TokenizedStringMsgs.UPN_DISAMBIGUATE_MESSAGE = "It looks like #~#MemberName_LS#~# is used with more than one account. Which account do you want to use?";
I am able to login to CRM 2011 online through the credentials used in Java code successfully, but when I used same credentials in the code I am getting the above login issue response.
Please let me know if I am missing anything in the above code.
I am tring to perform Digest Authentication using the HttpClient library, but I keep getting: HTTP/1.1 401 Unauthorized.
When I try the request from Firefox it works fine and I get a response correctly, so I know the server authentication is working fine.
Update: moved Working code to answer.
The following code worked for me
import java.util.Random;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
/**
* A simple example that uses HttpClient to execute an HTTP request against a
* target site that requires user authentication.
*/
public class RestClient {
public static void main(String args[]) throws Exception {
HttpHost targetHost = new HttpHost("localhost", 8001, "http");
DefaultHttpClient httpclient = new DefaultHttpClient();
final String userName = "admin";
final String password = "password";
httpclient.getCredentialsProvider().setCredentials(
new AuthScope("localhost", 8001),
new UsernamePasswordCredentials(userName, password));
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate DIGEST scheme object, initialize it and add it to the local
// auth cache
DigestScheme digestAuth = new DigestScheme();
// Suppose we already know the realm name
digestAuth.overrideParamter("realm", "some realm");
// Suppose we already know the expected nonce value
digestAuth.overrideParamter("nonce", "whatever");
authCache.put(targetHost, digestAuth);
// Add AuthCache to the execution context
BasicHttpContext localcontext = new BasicHttpContext();
localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
HttpGet httpget = new HttpGet("http://localhost:8001/rest/test");
try {
HttpResponse response = httpclient.execute(targetHost, httpget, localcontext);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
}
EntityUtils.consume(entity);
} finally {
httpclient.getConnectionManager().shutdown();
}
}
}
How to make HTTPClient use custom User-Agent header?
The following code submits empty user-agent. What am I missing?
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
public class TestHTTP {
public static void main(String[] args) throws ClientProtocolException, IOException {
HttpGet request = new HttpGet("http://tool.keepmeapi.com/echo");
HttpContext HTTP_CONTEXT = new BasicHttpContext();
HTTP_CONTEXT.setAttribute(CoreProtocolPNames.USER_AGENT, "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13");
request.setHeader("Referer", "http://www.google.com");
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request, HTTP_CONTEXT);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 400) {
throw new IOException("Got bad response, error code = " + response.getStatusLine().getStatusCode());
}
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
EntityUtils.consume(entity);
}
}
}
Note: The solution is for users using the old httpcomponents 4.2 and before.
The line
request.setHeader("User-Agent", "MySuperUserAgent");
is missing. Add it and enjoy.
Note: Starting from httpcomponents 4.3 this solution is deprecated.
You can also set a global user agent value instead of per request:
String userAgent = "NewUseAgent/1.0";
HttpClient httpClient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, userAgent);
With httpcomponents 4.3 you should use the client builder to set the user agent:
HttpClient httpClient = HttpClients.custom()
.setUserAgent("my UserAgent 5.0")
.build();
httpClient.execute(new HttpGet("http://www.google.de"));