I am implementing a proxy server which will be used to security purposes, and I am implementing it in Java, using Httpclient and native Sockets. The problem comes out when using SSL connections and even normal connections, because the browswer alaways detects it as XXS/cross side scripting threats.
The main code I am using to make the traffic flow is:
HttpResponse response = null;
try {
SSLSocketFactory sf = new SSLSocketFactory(acceptingTrustStrategy,
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("https", socket.getPort(), sf));
ClientConnectionManager ccm = new PoolingClientConnectionManager(registry);
DefaultHttpClient httpClient = new DefaultHttpClient(ccm);
httpClient.getConnectionManager().getSchemeRegistry().register(
new Scheme("https", 443, SSLSocketFactory.getSystemSocketFactory())
);
if (!urlToCall.contains("http://") || !urlToCall.contains("https://")) {
urlToCall = "https://" + urlToCall;
}
HttpGet getMethod = new HttpGet(urlToCall);
response = httpClient.execute(getMethod);
} finally {
}
InputStream is = null;
if (response.getStatusLine().getStatusCode() == 200 && response != null) {
try {
is = response.getEntity().getContent();
out.writeBytes(inputStreamToString(is));
} catch (IOException ioe) {
ProxyThread.LOGGER.debug(ProxyThread.LOGGER.getName(), ioe);
} finally {
rd.close();
}
}
Is there anyone with good idea for making traffic flow with SSL or NOT?
Related
This is my first post here, but its one I've been struggling with for two days without any result.
I am installing a Java application on a hosted machine that has an internet proxy server.
When I use web browsers on this particular machine, they don't require any authentication - just the proxy host and port details.
When I run the following simple program that uses a UrlConnection, all it requires to get it running correctly are the proxy host and port also.
public class TestProxyConnectionUrlConnection {
public void runUrlConnection() {
try {
String host = "proxy-local.net";
String port = "8080";
System.setProperty( "http.proxyHost", host);
System.setProperty( "http.proxyPort", port);
System.setProperty( "http.useProxy", "true");
URL url = new URL("http://mydomainb.com/myservice");
URLConnection yc = url.openConnection();
yc.setRequestProperty("Connection", "keep-alive");
yc.setDoOutput(true);
yc.setDoInput(true);
DataOutputStream wr = new DataOutputStream(yc.getOutputStream());
wr.writeBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?><xmlcontent>content</xmlcontent>");
wr.flush();
wr.close();
BufferedReader in = new BufferedReader( new InputStreamReader( yc.getInputStream()));
try {
String inputLine;
String response = "";
while ((inputLine = in.readLine()) != null) {
response = inputLine;
}
}
finally {
in.close();
}
System.out.println(response);
}
catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
However, when I run code that uses Apache Commons HttpClient to talk to the server, as per the next bit of code, the proxy server is responding with a 407 error, and requesting NTLM or Kerberos authentication.
* Note we are stuck in using HttpCommons v3.1 for the time being due to a web-service product that uses it also.
public class TestProxyConnectionHttpCommons {
public void runHttpClient() throws Exception {
HttpClient httpclient = new HttpClient();
try {
String host = "proxy-local.net";
String port = "8080";
ProxyHost pxy = new ProxyHost(host, Integer.parseInt(port));
httpclient.getHostConfiguration().setProxyHost( pxy);
PostMethod currentMethod = new PostMethod( "http://mydomainb.com/myservice");
currentMethod.setRequestHeader( "Content-type", "text/xml; charset=UTF-8");
currentMethod.setRequestBody( "<?xml version=\"1.0\" encoding=\"UTF-8\"?><xmlcontent>content</xmlcontent>");
// The following line doesn't have any impact.
//currentMethod.setDoAuthentication(false);
final int iResult = httpclient.executeMethod( currentMethod);
String sResult = currentMethod.getResponseBodyAsString();
System.out.println(sResult);
}
finally {
httpclient = null;
}
}
}
Does anyone know why HttpClient would be resulting in an authentication challenge, but using a standard UrlConnection gets through the proxy server fine? Is there something fundamental that I'm doing wrong?
I'm working on a Java program that will send POST requests to a website for my company to use. We do not own this website, they are separate from us. I've been fighting with various ways to actually pass it the very picky parameters it wants in order for me to do work on it from a program (as opposed to doing it manually).
I've found that the Apache HttpClient 4.3 seems to be my best route for actually trying to access it, anything results in a angry response from the website telling me my username and password and not valid/authorized.
But then I got an error because the site certificate doesn't match, I contacted their support and they reportedly share an infrastructure with another site so the certificate mismatch is expected.
So I went commandline and generated a keystore, passed that to the program and then got the error "java.security.cert.CertificateException: No subject alternative DNS name matching".
Some hunting lead me to utilize a verifier, which removed errors.
Then I realized that I can't make URLConnection/HttpsURLConnection and HttpClient/HttpPost work together. That's where I'm stuck. I'm not sure how to make the code that handles my keystore, TrustManager, SSLSocketFactory, etc connect to the part where I actually have to connect and POST.
Code that handles the certificates and verification:
InputStream in = new FileInputStream(new File("C:\\Program Files (x86)\\Java\\jre7\\bin\\my.keystore"));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, "blahblah".toCharArray());
in.close(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] {defaultTrustManager}, null);
javax.net.ssl.SSLSocketFactory sslSocketFactory = context.getSocketFactory();
URL url = new URL("https://emailer.driveclick.com/dbadmin/xml_post.pl");
URLConnection con = url.openConnection();
((HttpsURLConnection) con).setSSLSocketFactory(sslSocketFactory);
((HttpsURLConnection) con).setHostnameVerifier(new Verifier());
con.connect();
in = con.getInputStream();
Code that should be connecting me to the website:
try {
//log into the website
String url2 = "https://emailer.driveclick.com/dbadmin/xml_post.pl";
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url2);
post.setHeader("User-Agent", USER_AGENT);
List<BasicNameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("username", "namefoo"));
urlParameters.add(new BasicNameValuePair("api_password", "passfoo"));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
org.apache.http.HttpResponse response = client.execute(post);
System.out.println("\nSending 'POST' request to URL : " + url2);
System.out.println("Post parameters : " + post.getEntity());
System.out.println("Response Code : " + 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 (UnsupportedEncodingException ex) {
Logger.getLogger(LastFileMove.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(LastFileMove.class.getName()).log(Level.SEVERE, null, ex);
}
EDIT: I forgot to include the little class I made for the Verifier that I referenced.
public class Verifier implements HostnameVerifier
{
public boolean verify(String arg0, SSLSession arg1) {
return true; // mark everything as verified
}
}
Update 5/8/2014
SSLConext and Verifier are now set up like this:
SSLContext sslContext = SSLContexts.custom()
.useTLS()
.loadTrustMaterial(ks)
.build();
X509HostnameVerifier verifier = new AbstractVerifier()
{
#Override
public void verify(final String host, final String[]
cns, final String[] subjectAlts) throws SSLException
{
verify(host, cns, subjectAlts, true);
}
};
And I've gone ahead and changed my HttpClient to a closeable one here:
CloseableHttpClient client = HttpClients.custom()
sslSocketFactory)
.setHostnameVerifier(verifier)
.setSslcontext(sslContext)
.build();
And I'm back to having "javax.net.ssl.SSLException: hostname in certificate didn't match" errors. Suggestions?
I have no idea how Verifier is implemented but this code snippet demonstrates how one can create a custom hostname verifier none of those shipped with HttpClient fits their needs
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream in = new FileInputStream(new File("C:\\Program Files (x86)\\Java\\jre7\\bin\\my.keystore"));
try {
ks.load(in, "blahblah".toCharArray());
} finally {
in.close();
}
SSLContext sslContext = SSLContexts.custom()
.useTLS()
.loadTrustMaterial(ks)
.build();
X509HostnameVerifier verifier = new AbstractVerifier() {
#Override
public void verify(final String host, final String[] cns, final String[] subjectAlts) throws SSLException {
verify(host, cns, subjectAlts, true);
}
};
CloseableHttpClient hc = HttpClients.custom()
.setSslcontext(sslContext)
.setHostnameVerifier(verifier)
.build();
I am trying to setup 2 - way SSL between client and server using HttpClient 4.3.3 library for a WebApp to communicate with a server component.
I have the client / server commuicating successfully over SSL in what I believe looks to be one-way SSL in that the CA hierarchy is not being strictly validated from what I can see, or maybe HttpClient is hiding all the details. It also seems quite difficult to get the peer certificate chain, this seems to be accessible through SSLSession object which would be present in strict JSSE interaction but HttpClient abstracts away from and does not seem possible to access?
Looking at the debug SSL logging it all seems to be fine, I guess i just wanted to confirm that 2 way SSL is happening even if it is happening within HttpClient.
Also, the TrustStrategy only seems to access the client Certificate chain and regardless of true or false returned for 'isTrusted' never seems to behave differently.
TLDR; is this 2 way SSL, if not what needs to change? How does one get access to peer certificate chain using HttpClient? Does the TrustStrategy actually do anything?
This is my code thus far which works with the server which I know to be running SSL:
try{
KeyStore trustStore = KeyStore.getInstance(keystoreType, keystoreProvider);
FileInputStream instream = new FileInputStream(new File("/path/to/keystore"));
try {
trustStore.load(instream,keystorePassword.toCharArray());
} finally {
instream.close();
}
//establish trust strategy
TrustStrategy trustStrategy = new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
for(X509Certificate cert : x509Certificates){
System.out.println("cert = " + cert);
}
return true;
}
};
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(trustStore, keystorePassword.toCharArray())
.loadTrustMaterial(trustStore, trustStrategy).build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
try {
HttpPost post = new HttpPost(existingSSLServerURL);
HttpEntity requestEntity = new ByteArrayEntity(sampleAuthenticationForSSL.getBytes("UTF-8"));
post.setEntity(requestEntity);
System.out.println("executing request" + post.getRequestLine());
CloseableHttpResponse response = httpclient.execute(post);
try {
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
BufferedReader in = new BufferedReader(new InputStreamReader(entity.getContent()));
String inputline = null;
while((inputline = in.readLine()) != null){
System.out.println(inputline);
}
}
EntityUtils.consume(entity);
} finally {
response.close();
}
} finally {
httpclient.close();
}
}catch(Exception e){
e.printStackTrace();
fail();
}
I'm writing a Java program that connects to a web server (HTTPS and requires username/password) with this code, but it hangs when it reaches the execute call:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream instream = new FileInputStream(new File("D:/jssecacerts"));
try {
trustStore.load(instream, "certspassword".toCharArray());
} finally {
try { instream.close(); } catch (Exception ignore) {}
}
SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);
Scheme sch = new Scheme("https", 443, socketFactory);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
HttpGet httpget = new HttpGet("https://server/path/default.aspx");
httpclient.getCredentialsProvider().setCredentials(
new AuthScope("server", 443),
new UsernamePasswordCredentials("user", "pass"));
System.out.println("executing request" + httpget.getRequestLine());
HttpResponse response = httpclient.execute(httpget);
This is what I've tried in order to isolate the problem:
If I comment out the setCredentials line, it doesn't hang and the server instantly returns a HTTP/1.1 401 Unauthorized response
It doesn't matter if I provide a valid username/password or not
I've tried to specify timeouts with different methods but it remains hung after the timeout interval is over
I'm connecting my Application to a REST type webservice. I'm using the apache http library, the request is a standard post request, ran in a background thread.
Now my problem is that if I'm using
http://myserver.com/api/command
it works and I get the proper response, but the same url with https:
https://myserver.com/api/command
I get an empty response. The http header is even 200 OK.
BOTH of these work on 2.0.3 but not on 4.0.3. On 4.0.3 the API seems to work only if I use plain http, with https I get empty responses.
This is the code:
#Override
protected HttpResponse doInBackground(String... params) {
String link = params[0];
HttpClient client = createHttpClient();
try {
HashMap<String, ContentBody> files = ApiManager.getFiles();
MultipartEntity mpEntity = new MultipartEntity();
if(files != null) {
for(String i : files.keySet()) {
ContentBody k = files.get(i);
mpEntity.addPart(i, k);
}
}
if(this.callParameters != null) {
for(NameValuePair i : this.callParameters) {
StringBody sb = new StringBody((String)i.getValue(),"text/plain",Charset.forName("UTF-8"));
mpEntity.addPart(i.getName(), sb);
}
}
httppost.setEntity(mpEntity);
// Execute HTTP Post Request
Log.d("ApiTask","Executing request: "+httppost.getRequestLine());
HttpResponse response = null;
response = client.execute(httppost);
client.getConnectionManager().shutdown();
return response;
}
catch(UnknownHostException e) {
exception = e;
return null;
}
catch (IOException e) {
exception = e;
return null;
}
catch(Exception e) {
return null;
}
}
#Override
protected void onPostExecute(HttpResponse result) {
System.out.println("STATUS:"+result.getStatusLine());
try {
StringBuilder responseText = this.inputStreamToString(result.getEntity().getContent());
System.out.println("RESPONSE:"+responseText);
}
catch(Exception e) {
System.out.println("Error");
}
}
private HttpClient createHttpClient() {
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
HttpConnectionParams.setConnectionTimeout(params, 10000);
HttpConnectionParams.setSoTimeout(params, 10000);
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);
return new DefaultHttpClient(conMgr, params);
}
Thank you in advance