Unable to tunnel through proxy. Proxy returns "HTTP/1.1 407" via https - authentication

I try to connect to a server via https that requires authentication.Moreover, I have an http proxy in the middle that also requires authentication. I use ProxyAuthSecurityHandler to authenticate with the proxy and BasicAuthSecurityHandler to authenticate with the server.
Receiving java.io.IOException: Unable to tunnel through proxy.
Proxy returns "HTTP/1.1 407 Proxy Auth Required"
at sun.net.www.protocol.http.HttpURLConnection.doTunneling(HttpURLConnection.java:1525)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect (AbstractDelegateHttpsURLConnection.java:164)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at org.apache.wink.client.internal.handlers.HttpURLConnectionHandler.processRequest(HttpURLConnectionHandler.java:97)
I noticed that the implementation of ProxyAuthSecurityHandler is expecting response code 407 however, during debug we never get to the second part due to the IOException thrown.
Code snap:
ClientConfig configuration = new ClientConfig();
configuration.connectTimeout(timeout);
MyBasicAuthenticationSecurityHandler basicAuthProps = new MyBasicAuthenticationSecurityHandler();
basicAuthProps.setUserName(user);
basicAuthProps.setPassword(password);
configuration.handlers(basicAuthProps);
if ("true".equals(System.getProperty("setProxy"))) {
configuration.proxyHost(proxyHost);
if ((proxyPort != null) && !proxyPort.equals("")) {
configuration.proxyPort(Integer.parseInt(proxyPort));
}
MyProxyAuthSecurityHandler proxyAuthSecHandler =
new MyProxyAuthSecurityHandler();
proxyAuthSecHandler.setUserName(proxyUser);
proxyAuthSecHandler.setPassword(proxyPass);
configuration.handlers(proxyAuthSecHandler);
}
restClient = new RestClient(configuration);
// create the createResourceWithSessionCookies instance to interact with
Resource resource = getResource(loginUrl);
// Request body is empty
ClientResponse response = resource.post(null);
Tried using wink client versions 1.1.2 and also 1.2.1. the issue repeats in both.

What I found out is that when trying to pass through a proxy using https url we first send CONNECT and only then try to send the request. The proxy server cannot read any headrs we attach to the request, cause it doesn't have the key to decrypt the traffic.
This means that the CONNECT should already have the user/pass to the proxy to pass this stage.
here is a code snap I used - that works for me:
import sun.misc.BASE64Encoder;
import java.io.*;
import java.net.*;
public class ProxyPass {
public ProxyPass(String proxyHost, int proxyPort, final String userid, final String password, String url) {
try {
/* Create a HttpURLConnection Object and set the properties */
URL u = new URL(url);
Proxy proxy =
new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
HttpURLConnection uc = (HttpURLConnection)u.openConnection(proxy);
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType().equals(RequestorType.PROXY)) {
return new PasswordAuthentication(userid, password.toCharArray());
}
return super.getPasswordAuthentication();
}
});
uc.connect();
/* Print the content of the url to the console. */
showContent(uc);
} catch (IOException e) {
e.printStackTrace();
}
}
private void showContent(HttpURLConnection uc) throws IOException {
InputStream i = uc.getInputStream();
char c;
InputStreamReader isr = new InputStreamReader(i);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
public static void main(String[] args) {
String proxyhost = "proxy host";
int proxyport = port;
String proxylogin = "proxy username";
String proxypass = "proxy password";
String url = "https://....";
new ProxyPass(proxyhost, proxyport, proxylogin, proxypass, url);
}
}
if you are using wink - like I do, you need to set the proxy in the ClientConfig and before passing it to the RestClient set the default authenticator.
ClientConfig configuration = new ClientConfig();
configuration.connectTimeout(timeout);
BasicAuthenticationSecurityHandler basicAuthProps = new BasicAuthenticationSecurityHandler();
basicAuthProps.setUserName(user);
basicAuthProps.setPassword(password);
configuration.handlers(basicAuthProps);
if (proxySet()) {
configuration.proxyHost(proxyHost);
if ((proxyPort != null) && !proxyPort.equals("")) {
configuration.proxyPort(Integer.parseInt(proxyPort));
}
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType().equals(RequestorType.PROXY)) {
return new PasswordAuthentication(proxyUser), proxyPass.toCharArray());
}
return super.getPasswordAuthentication();
}
});
}
restClient = new RestClient(configuration);
Resource resource = getResource(loginUrl);
// Request body is empty
ClientResponse response = resource.post(null);
if (response.getStatusCode() != Response.Status.OK.getStatusCode()) {
throw new RestClientException("Authentication failed for user " + user);
}

If Ilana Platonov's answer doesn't work, try editing the variables :
jdk.http.auth.tunneling.disabledSchemes
jdk.http.auth.proxying.disabledSchemes

Related

API Chorus Pro Oauth2 authentication in Java

I created an account on https://developer.aife.economie.gouv.fr/ website and I want to try API on the sandbox. For this an application has been generated
For this application, I obtain API key and OAuth2 Credentials. Here are my previous API keys.
By reading the documentation, I have the following entry points for authentication
My objective is to get authenticated and get an auth token in order to consume this API. Here is my code:
package com.oauth.app;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class OAuthApp {
/**
* URL for requesting OAuth access tokens.
*/
private static final String TOKEN_REQUEST_URL =
"https://sandbox-oauth.aife.economie.gouv.fr/api/oauth/token";
/**
* Client ID of your client credential. Change this to match whatever credential you have created.
*/
private static final String CLIENT_ID =
"1f80aa43-e12f-4e1c-ad42-87ec16baf060";
/**
* Client secret of your client credential. Change this to match whatever credential you have created.
*/
private static final String CLIENT_SECRET =
"a232af0e-513e-4a64-9977-410d237dc421";
/**
* Account on which you want to request a resource. Change this to match the account you want to
* retrieve resources on.
*/
private static final String ACCOUNT_ID =
"a232af0e-513e-4a64-9977-410d237dc421";
/**
* Request a fresh access token using the given client ID, client secret, and token request URL,
* then request the resource at the given resource URL using that access token, and get the resource
* content. If an exception is thrown, print the stack trace instead.
*
* #param args Command line arguments are ignored.
*/
public static void main(String[] args) {
try {
OAuthClient client = new OAuthClient(new URLConnectionClient());
System.out.println("OAuthClient " + client.toString());
OAuthClientRequest request =
OAuthClientRequest.tokenLocation(TOKEN_REQUEST_URL)
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
// .setScope() here if you want to set the token scope
.buildQueryMessage();
request.addHeader("Accept", "application/json");
// request.addHeader("Content-Type", "application/json");
// request.addHeader("Authorization", base64EncodedBasicAuthentication());
System.out.println("OAuthClientRequest body\n\t " + request.getBody());
System.out.println("OAuthClientRequest headers\n\t " + request.getHeaders());
System.out.println("OAuthClientRequest locationUri\n\t " + request.getLocationUri());
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
String token = client.accessToken(
request,
OAuth.HttpMethod.GET,
OAuthJSONAccessTokenResponse.class).getAccessToken();
} catch (OAuthSystemException | OAuthProblemException e) {
e.printStackTrace();
}
}
}
I obtain this in my console:
OAuthClient org.apache.oltu.oauth2.client.OAuthClient#7e0ea639
OAuthClientRequest body
null
OAuthClientRequest headers
{Accept=application/json, Content-Type=application/json}
OAuthClientRequest locationUri
https://sandbox-oauth.aife.economie.gouv.fr/api/oauth/token?grant_type=client_credentials&client_secret=a232af0e-513e-4a64-9977-410d237dc421&client_id=42b214ec-7eaf-4f37-aeb5-ae91057a0e27
OAuthProblemException{error='unsupported_response_type', description='Invalid response! Response body is not application/json encoded', uri='null', state='null', scope='null', redirectUri='null', responseStatus=0, parameters={}}
at org.apache.oltu.oauth2.common.exception.OAuthProblemException.error(OAuthProblemException.java:63)
at org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse.setBody(OAuthJSONAccessTokenResponse.java:76)
at org.apache.oltu.oauth2.client.response.OAuthClientResponse.init(OAuthClientResponse.java:92)
at org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse.init(OAuthAccessTokenResponse.java:65)
at org.apache.oltu.oauth2.client.response.OAuthClientResponse.init(OAuthClientResponse.java:101)
at org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse.init(OAuthAccessTokenResponse.java:60)
at org.apache.oltu.oauth2.client.response.OAuthClientResponse.init(OAuthClientResponse.java:120)
at org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory.createCustomResponse(OAuthClientResponseFactory.java:82)
at org.apache.oltu.oauth2.client.URLConnectionClient.execute(URLConnectionClient.java:111)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:65)
at com.oauth.app.OAuthApp.main(OAuthApp.java:101)
I obtain this error message:
OAuthProblemException{error='unsupported_response_type', description='Invalid response! Response body is not application/json encoded'
I also tried to use a curl call to the API :
curl –k –H "content-type :application/x-www-form-urlencoded" –d "grant_type=client_credentials&client_id=42b214ec-7eaf-4f37-aeb5-ae91057a0e27&client_secret=a232af0e-513e-4a64-9977-410d237dc421&scope=openid" –X POST https://sandbox-oauth.aife.finances.rie.gouv.fr/api/oauth/token
curl: (6) Could not resolve host: -k
curl: (6) Could not resolve host: -H
curl: (3) Port number ended with 'a'
curl: (6) Could not resolve host: -d
curl: (6) Could not resolve host: grant_type=client_credentials&client_id=42b214ec-7eaf-4f37-aeb5-ae91057a0e27&client_secret=a232af0e-513e-4a64-9977-410d237dc421&scope=openid
curl: (6) Could not resolve host: -X
curl: (6) Could not resolve host: POST
curl: (6) Could not resolve host: sandbox-oauth.aife.finances.rie.gouv.fr
Ok i finally solved my own issue. There was no need to use OAuth stuff.
It's divided onto 2 classes. This code is just for testing purpose.
public class OAuthApp {
private static final String TOKEN_REQUEST_URL = "https://sandbox-oauth.aife.economie.gouv.fr/api/oauth/token";
private static final String CLIENT_ID = "xxxxxx";
private static final String CLIENT_SECRET = "xxxxxx";
private static final String GRANT_TYPE = "client_credentials";
private static final String SCOPE = "openid";
public static void main(String[] args) throws IOException {
try {
Map<String, String> headers = new HashMap<>();
HttpsPostForm httpsPostForm = new HttpsPostForm(TOKEN_REQUEST_URL, "utf-8", headers);
httpsPostForm.addFormField("grant_type", GRANT_TYPE);
httpsPostForm.addFormField("client_id", CLIENT_ID);
httpsPostForm.addFormField("client_secret", CLIENT_SECRET);
httpsPostForm.addFormField("scope", SCOPE);
// Result
String response = httpsPostForm.finish();
System.out.println(response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
My second class is just building the HTTPS request and set the headers elements. The empty trust manager helps to avoid error messages.
public class HttpsPostForm {
private HttpsURLConnection conn;
private Map<String, Object> queryParams;
private String charset;
public HttpsPostForm(String requestURL, String charset, Map<String, String> headers, Map<String, Object> queryParams) throws IOException {
this.charset = charset;
if (queryParams == null) {
this.queryParams = new HashMap<>();
} else {
this.queryParams = queryParams;
}
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
URL url = new URL(requestURL);
conn = (HttpsURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoOutput(true); // indicates POST method
conn.setDoInput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
if (headers != null && headers.size() > 0) {
Iterator<String> it = headers.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
String value = headers.get(key);
conn.setRequestProperty(key, value);
}
}
}
public HttpsPostForm(String requestURL, String charset, Map<String, String> headers) throws IOException {
this(requestURL, charset, headers, null);
}
public HttpsPostForm(String requestURL, String charset) throws IOException {
this(requestURL, charset, null, null);
}
public void addFormField(String name, Object value) {
queryParams.put(name, value);
}
public void addHeader(String key, String value) {
conn.setRequestProperty(key, value);
}
private byte[] getParamsByte(Map<String, Object> params) {
byte[] result = null;
StringBuilder postData = new StringBuilder();
for (Map.Entry<String, Object> param : params.entrySet()) {
if (postData.length() != 0) {
postData.append('&');
}
postData.append(this.encodeParam(param.getKey()));
postData.append('=');
postData.append(this.encodeParam(String.valueOf(param.getValue())));
}
try {
result = postData.toString().getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
private String encodeParam(String data) {
String result = "";
result = URLEncoder.encode(data, StandardCharsets.UTF_8);
return result;
}
public String finish() throws IOException {
String response = "";
byte[] postDataBytes = this.getParamsByte(queryParams);
conn.getOutputStream().write(postDataBytes);
// Check the http status
int status = conn.getResponseCode();
if (status == HttpsURLConnection.HTTP_OK) {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = conn.getInputStream().read(buffer)) != -1) {
result.write(buffer, 0, length);
}
response = result.toString(this.charset);
conn.disconnect();
} else {
throw new IOException("Server returned non-OK status: " + status);
}
return response;
}
}
Finally I can print my Json string :
{
"access_token":"Js1NYJvtQREj0I0Dz5b0qrMh8gjJBlltJAit2Yx6BGJDloixPv2JwB",
"token_type":"Bearer",
"expires_in":3600,
"scope":"openid resource.READ"
}
I also had some difficulties with Chorus API but I achieve to get the tokenKey with that with the same method but buildBodyMessage() at the end.
// Création requête pour obtenir le token Oauth2 API CHORUS
request = OAuthClientRequest
.tokenLocation(urlToken)
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId(clientid)
.setClientSecret(clientsecret)
.setScope(OidcScopes.OPENID)
.buildBodyMessage();
// Ajout du Cpro-account
request.addHeader("cpro-account", cproAccount);
tokenChorus = client.accessToken(request, OAuth.HttpMethod.POST, OAuthJSONAccessTokenResponse.class)
.getAccessToken();
that create token formated in String. And afterthat you must create HttpUrlConnection with this token with headers like that
HttpURLConnection connexion = null;
try {
URL url = new URL(currentUrl);
connexion = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
e.printStackTrace();
}
connexion.setRequestProperty("Content-type", "application/json");
connexion.setRequestProperty("Authorization", "Bearer " + tokenChorus);
connexion.setRequestProperty("cpro-account", cproAccount);
try {
connexion.setRequestMethod("POST");
} catch (ProtocolException e) {
e.printStackTrace();
}
connexion.setDoInput(true);
connexion.setDoOutput(true);
return connexion;

Apache HttpClient - Default protocol

I am using Apache HttpClient to send a POST requests. How can I determine which PROTOCOL my Apache HttpClient instance is using for sending "https://" requests. I use following code block to send my POST requests.
public void sendPostURL(String url, HashMap<String, String>params, String user, String pass) {
HttpClient client = new HttpClient();
String urlContent = "";
PostMethod method = new PostMethod("https://...");
// Prepare connection information
client.getParams().setParameter("http.useragent", "MyApp");
if ( (user != null) &&(pass != null) ) {
client.getParams().setAuthenticationPreemptive(true);
client.getState().setCredentials(AuthScope.ANY, (new UsernamePasswordCredentials(user, pass)));
}
// Prepare parameters
for (Map.Entry<String, String> entry : params.entrySet()) {
method.addParameter(entry.getKey(), ((entry.getValue() != null) ? entry.getValue().toString() : ""));
}
try{
// HTTP execution
int returnCode = client.executeMethod(method);
} catch (Exception e) {
// Exception
e.printStackTrace();
} finally {
method.releaseConnection();
}
}
Please guide me on how can I get the PROTOCOL that HttpClient is using to send the request. Also how can I override the PROTOCOL used. Hoping for a solution. Thanks in advance.
The protocol is HTTPS, is it not ?

HTTP Requests in Glass GDK

I am implementing a GDK application and need to do in my application some HTTP Post requests. Do I send the HTTP requests the same way as on android phone or there is some other way of doing it? (I have tried the code that I am using on my phone and it's not working for glass.)
thanks for your help in advance.
You can make any post request like in smartphones, but ensure you make the requests using an AsyncTask.
For example:
private class SendPostTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
// Make your request POST here. Example:
myRequestPost();
return null;
}
protected void onPostExecute(Void result) {
// Do something when finished.
}
}
And you can call that asynctask anywhere with:
new SendPostTask().execute();
And example of myRequestPost() may be:
private int myRequestPost() {
int resultCode = 0;
String url = "http://your-url-here";
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
// add headers you want, example:
// post.setHeader("Authorization", "YOUR-TOKEN");
List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("id", "111111"));
nameValuePairs.add(new BasicNameValuePair("otherField", "your-other-data"));
try {
post.setEntity(new UrlEncodedFormEntity(urlParameters));
HttpResponse response = client.execute(post);
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Post parameters : " + post.getEntity());
System.out.println("Response Code : " +
response.getStatusLine().getStatusCode());
resultCode = response.getStatusLine().getStatusCode();
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
System.out.println(result.toString());
} catch (Exception e) {
Log.e("POST", e.getMessage());
}
return resultCode;
}

httpcomponents's ssl connection results in socket is closed

I am trying to get some data from webserver which works fine with http.
But when I try https(ssl connection), I get the exceptions like below.
I get the http status code 200 and response content length 2230 which is correct.
java.net.SocketException: Socket is closed
at sun.security.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.java:1483)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:92)
at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:166)
at org.apache.http.impl.io.SocketInputBuffer.fillBuffer(SocketInputBuffer.java:90)
at org.apache.http.impl.io.AbstractSessionInputBuffer.read(AbstractSessionInputBuffer.java:183)
at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:144)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:121)
My code is like below with apache httpcomponents httpclient(4.2.5) library.
try {
HttpPost httppost = new HttpPost(uri);
HttpHost targetHost = new HttpHost(HOST_NAME, HOST_PORT, PROTOCOL);
InputStreamEntity reqEntity = new InputStreamEntity(new ByteArrayInputStream(request), -1);
String contentType = TSPConstants.CONST_TSA_CONTENT_TYPE_TSREQUEST;
reqEntity.setContentType(contentType);
reqEntity.setChunked(true);
// It may be more appropriate to use FileEntity class in this particular
// instance but we are using a more generic InputStreamEntity to demonstrate
// the capability to stream out data from any arbitrary source
//
// FileEntity entity = new FileEntity(file, "binary/octet-stream");
httppost.setEntity(reqEntity);
//Authentication
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
new UsernamePasswordCredentials(id, 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(targetHost, basicAuth);
// Add AuthCache to the execution context
BasicHttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute(ClientContext.AUTH_CACHE, authCache);
httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
//SSL
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme sch = new Scheme("https", HOST_PORT, ssf);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
System.out.println("executing request " + httppost.getRequestLine());
httpclient.execute(httppost, httpContext);
HttpResponse response = send(request);
HttpEntity resEntity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (resEntity != null) {
System.out.println("Response content length: " + resEntity.getContentLength());
System.out.println("Chunked?: " + resEntity.isChunked());
}
EntityUtils.consume(resEntity);
resEntity.getContent()
} finally {
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
Basically the answer gave #Avner in the comment.
The problem (for me) was, that the response was closed before the entity was read.
I did something like this, which was wrong:
HttpEntity entity = null;
try (CloseableHttpResponse response = client.execute(request)) {
entity = response.getEntity();
}
read(entity);
The following worked:
try (CloseableHttpResponse response = client.execute(request)) {
HttpEntity entity = response.getEntity();
read(entity);
}
The maybe not so obvious part: The try-with-resources block in the first example closed the stream, before it was read.

Solr 4 with basic authentication

I am trying to connect to solr using solrj. My solr instance runs in jetty and is protected with basic authentication. I found these links that contain relevant information.
http://grokbase.com/t/lucene/solr-user/1288xjjbwx/http-basic-authentication-with-httpsolrserver
Preemptive Basic authentication with Apache HttpClient 4
However, I still get the following exception:
Caused by: org.apache.http.client.ClientProtocolException
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:822)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at org.apache.solr.client.solrj.impl.HttpSolrServer.request(HttpSolrServer.java:352)
... 5 more
Caused by: org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity.
at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:625)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:464)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
... 8 more
I have also attached a snippet of the code I am using.
public static void main(String[] args) throws SolrServerException, IOException {
HttpSolrServer server = new HttpSolrServer("http://localhost:8983/solr/");
DefaultHttpClient m_client =(DefaultHttpClient)server.getHttpClient();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(USERNAME, PASSWORD);
m_client.addRequestInterceptor(new PreemptiveAuthInterceptor(),0);
(((DefaultHttpClient)m_client).getCredentialsProvider()).setCredentials(new AuthScope("localhost",8983), credentials);
SolrInputDocument document = new SolrInputDocument();
document.addField("id",123213);
server.add(document);
server.commit();
}
}
class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
// If no auth scheme avaialble yet, try to initialize it
// preemptively
if (authState.getAuthScheme() == null) {
AuthScheme authScheme = (AuthScheme) context.getAttribute("preemptive-auth");
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
if (authScheme != null) {
Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
if (creds == null) {
throw new HttpException("No credentials for preemptive authentication");
}
authState.setAuthScheme(authScheme);
authState.setCredentials(creds);
}
}
}
Can anyone point me in the right direction? Thanks !!
i had the same problem when implementing partial documents update. i solved the problem by implementing PreemptiveAuthInterceptor. see below code
PoolingClientConnectionManager cxMgr = new PoolingClientConnectionManager(
SchemeRegistryFactory.createDefault());
cxMgr.setMaxTotal(100);
cxMgr.setDefaultMaxPerRoute(20);
DefaultHttpClient httpclient = new DefaultHttpClient(cxMgr);
httpclient.addRequestInterceptor(
new PreemptiveAuthInterceptor(), 0);
httpclient.getCredentialsProvider().setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(solrDto.getUsername(),
solrDto.getPassword()));
HttpSolrServer solrServerInstance = new HttpSolrServer(solrDto.getUrl(),
httpclient);
solrServerInstance.setRequestWriter(new BinaryRequestWriter());
solrServerInstance.setAllowCompression(true);
You also need:
private class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
public void process(final HttpRequest request, final HttpContext context)
throws HttpException, IOException {
AuthState authState = (AuthState) context
.getAttribute(ClientContext.TARGET_AUTH_STATE);
// If no auth scheme avaialble yet, try to initialize it
// preemptively
if (authState.getAuthScheme() == null) {
CredentialsProvider credsProvider = (CredentialsProvider) context
.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context
.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
Credentials creds = credsProvider.getCredentials(new AuthScope(
targetHost.getHostName(), targetHost.getPort()));
if (creds == null)
throw new HttpException(
"No credentials for preemptive authentication");
authState.setAuthScheme(new BasicScheme());
authState.setCredentials(creds);
}
}
}
According to the Solr Security - SolrJ section on Solr Wiki you should be able to do the following:
public static void main(String[] args) throws SolrServerException, IOException {
HttpSolrServer server = new HttpSolrServer("http://localhost:8983/solr/");
HttpClientUtil.setBasicAuth(server.getHttpClient(), USERNAME, PASSWORD);
SolrInputDocument document = new SolrInputDocument();
document.addField("id",123213);
server.add(document);
server.commit();
}
You need to add the JAR solr-solrj-4.0.0.jar for HttpClientUtil.
Then use the below code:
HttpSolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr/"+url);
HttpClientUtil.setBasicAuth((DefaultHttpClient) solrServer.getHttpClient(), "USERNAME", "PASSWORD");
That worked for me on Jdk 1.6 and tomcat 6