When using the Apache HttpComponents HttpClient library (4.0.2) I'm having a problem where the certificate doesn't get validated properly. The certificate is valid for the domain name (let's call it example.com) however it's getting validated against the IP address instead:
hostname in certificate didn't match: <123.123.123.123> !=
<*.example.com>
My code for making the connection is:
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, 5000);
DefaultHttpClient httpClient = new DefaultHttpClient(httpParams);
String url = "https://www.example.com";
HttpGet get = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(get);
String response = EntityUtils.toString(httpResponse.getEntity()).trim();
The certificate itself shows as valid when connecting through a web browser and is valid for the domain name I'm connecting to:
CN = *.example.com
The certificate is also added to the Java keystore (tested using regular HttpsURLConnection).
Any ideas why this code uses the IP address instead of the domain name?
Appears to be a known bug with HttpClient 4.0.2 - https://issues.apache.org/jira/browse/HTTPCLIENT-996
The bug suggests any of the following:
Upgrade to version 4.0.3 or newer
Downgrade to 4.0.1
Use the AllowAllHostnameVerifier
Related
I'm adding a cookie to Closeable HttpClient object and attempt to retrieve the same at the Server as below.
BasicClientCookie mCookie = new BasicClientCookie("myCookie", "dummyValue");
mCookie.setDomain(".myCookie.net");
mCookie.setPath("/");
mCookie.setSecure(true);
mCookie.setAttribute(ClientCookie.PATH_ATTR, "/");
mCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".myCookie.net");
mfCookies[0] = mCookie;
BasicCookieStore basicCookieStore = new BasicCookieStore();
basicCookieStore.addCookies(mfCookies);
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(
RequestConfig.custom().setConnectTimeout(connectionTimeOut).build())
.setDefaultCookieStore(basicCookieStore)
.setConnectionManager(poolingConnectionManager)
.build();
I connect to local url using HttpGet object as below
httpGet = new HttpGet(myLocalUrl);
httpResponse = httpClient.execute(httpGet);
HttpClient hits the local url correctly connecting to Rest end point on local host but when I try to retrieve cookies using code below
(HttpServletRequest) request.getCookies() ;//returns null
I get null.
Can someone please help - I'm using spring boot to make a Rest end point (server) and attempt to retrive the cookie.
I figured it out myself, actually I was setting the domain as .myCookie.net while I was connecting to http://localhost:8080/..., if running on local, the localhost should resolve to the domain name by dns so in this case .myCookie.net should be mapped to localhost in file /etc/hosts file.
eg set 127.0.0.1 www.myCookie.net in etc/hosts file and hit the url http://www.myCookie.net/...
If the url the httpclient connects to and the domain set in the cookie dont match, httpclient will just drop the cookies.
I'm trying to call heroku's developer api from java, but I get the following exception:
Exception in thread "main" javax.net.ssl.SSLException: hostname in certificate didn't match: <50.19.233.255> != <*.heroku.com>
My code looks like this:
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("https://api.heroku.com/apps");
String token = "d6d7ea6e-6e71-4f13-b0ff-ed9ee9d56c37";
request.addHeader("Authorization", "Bearer "+token);
HttpResponse response = client.execute(request);
If I try it with curl it works fine:
curl "https://api.heroku.com/apps" -H"Authorization: Bearer d6d7ea6e-6e71-4f13-b0ff-ed9ee9d56c37"
Why does the java code act differently to curl?
P.S. I'm aware that others have asked this questions, but all the answers, e.g:
https://stackoverflow.com/a/7266768
https://stackoverflow.com/a/3904473
https://stackoverflow.com/a/25356821
suggest that I should override the certificate hostname check, which surely defeats the point (and certainly isn't production-ready)?
This problem is described in Apache HttpClient resolving domain to IP address and not matching certificate.
It appears to be a bug in the version of HTTPClient you are using, where it compares the target IP instead of the target hostname with the subject certificate. Please use a fixed version of HTTPClient instead.
I'm running HttpClient 4.3.6 in Java 6. When I run the following code, the authentication appears to succeed. The Status Code returned is 200. However, I'm getting the following error message in the console:
WARNING: NEGOTIATE authentication error: Invalid name provided (Mechanism level: Could not load configuration file C:\Windows\krb5.ini (the system cannot find the file specified))
How do I eliminate this warning?
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpContext localContext = new BasicHttpContext();
HttpGet method = new HttpGet(url);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(host, 80),
new NTCredentials(userid, password, host, login_domain));
localContext.setAttribute(HttpClientContext.CREDS_PROVIDER, credsProvider);
String filePath = null;
// Execute the method.
CloseableHttpResponse clientResponse = httpclient.execute(method, localContext);
HttpEntity entity = clientResponse.getEntity();
int statusCode = clientResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
System.err.println("Method failed: " + method.getRequestLine());
}
You need to pass in a set of target preferred auth schemes:
Create your httpClient like this:
PoolingHttpClientConnectionManager connPool = new PoolingHttpClientConnectionManager();
connPool.setMaxTotal(200);
connPool.setDefaultMaxPerRoute(200);
// Authentication
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY, new NTCredentials(username, password, workstation, domain));
RequestConfig config = RequestConfig.custom().setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM)).build();
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connPool).setDefaultRequestConfig(config).build();
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
Yes I believe that, in fact, your authentication is successful and is probably just falling back to NTLM from Kerberos. My code looks similar to yours and in my application I'm connecting to SharePoint using HttpClient 4.3.5 in Java 7. When SharePoint is configured to "Negotiate" (Attempt Kerberos and then failover to NTLM), I will see a similar error to what you reported in the HttpClient generated logging, specifically:
Selected authentication options: [NEGOTIATE, NTLM]
Executing request GET /my/personal/user2/_api/web?$select=ServerRelativeUrl HTTP/1.1
Target auth state: CHALLENGED
Generating response to an authentication challenge using Negotiate scheme
init XXX.XXX.XXX.XXX:80
NEGOTIATE authentication error: org.ietf.jgss.GSSException, major code: 11, minor code: 0
major string: General failure, unspecified at GSSAPI level
minor string: Desired initLifetime zero or less
Generating response to an authentication challenge using ntlm scheme
Following that, it will successfully authenticate via NTLM. So, I read that error message as saying "Kerberos didn't work, now we'll use NTLM". As long as you're getting a 200 response, you should be good to go.
Are you sure authentication is happening successfully, if the website is set to Negotiate (Attempt Kerbero, then failover to NTLM) BASIC authentication would probably not be successful.
I have an application connecting to sites that require basic authentication. The sites are provided at run time and not known at compile time.
I am using HttpClient 4.2.
I am not sure if the code below is how I am supposed to specify basic authentication, but the documentation would suggest it is. However, I don't know what to pass in the constructor of AuthScope. I had thought that a null parameter meant that the credentials supplied should be used for all URLs, but it throws a NullPointerException, so clearly I am wrong.
m_client = new DefaultHttpClient();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(m_userName, m_password);
((DefaultHttpClient)m_client).getCredentialsProvider().setCredentials(new AuthScope((HttpHost)null), credentials);
AuthScope.ANY is what you're after: http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/auth/AuthScope.html
Try this:
final HttpClient client = new HttpClient();
client.getParams().setAuthenticationPreemptive(true);
client.getState().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(user.getUsername(), user.getPassword()));
final GetMethod method = new GetMethod(uri);
client.executeMethod(method);
From at least version 4.2.3 (I guess after version 3.X), the accepted answer is no longer valid. Instead, do something like:
private HttpClient createClient() {
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setContentCharset(params, "UTF-8");
Credentials credentials = new UsernamePasswordCredentials("user", "password");
DefaultHttpClient httpclient = new DefaultHttpClient(params);
httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, credentials);
return httpclient;
}
The JavaDoc for AuthScope.ANY says In the future versions of HttpClient the use of this parameter will be discontinued, so use it at your own risk. A better option would be to use one of the constructors defined in AuthScope.
For a discussion on how to make requests preemptive, see:
Preemptive Basic authentication with Apache HttpClient 4
I using HttpClient api to authenticate to a web site:
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(AuthScope.ANY_HOST, 443),
new UsernamePasswordCredentials(args[0], args[1]));
HttpGet httpget = new HttpGet("http://..........");
HttpResponse response = httpclient.execute(httpget);
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: "
+ entity.getContentLength());
}
I have this answer:
HTTP/1.1 403 Forbidden
Response content length: -1
But with a browser i have access to this page with the same login and password !!!!
How can i fix this problem ?
You construct the AuthScope object with the port parameter set to 443 (default port for HTTPS). However, you create the HttpGet object with the URL pointing to HTTP (with default port 80).
Either try to construct the AuthScope using:
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT)
or make sure that ports will match.
You need to look carefully at how the browser is actually authenticating.
What you are trying to do is (I think) send the credentials using HTTP Basic Authentication. If the site is set up to only allow form-based authentication and a session cookie, then it will ignore the header containing the credentials.
Check if the Version of the HttpClient you are using is whats causing the 403.
Try
HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.build();