SSL authentication not works in Mule ESB project (illegal_parameter) - java

I wrote some code which authenticates in HTTPS server over SSL. It working fine.
Now I have to move this part to my Mule ESB project.
Here is my working method:
public boolean authenticate() {
try {
System.setProperty("jsse.enableSNIExtension", "false");
System.setProperty("com.sun.net.ssl.enableECC", "false");
CookieManager manager = new CookieManager();
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);
URL url = new URL("https://...");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setUseCaches(false);
con.setInstanceFollowRedirects(true);
con.setConnectTimeout(5000);
con.setReadTimeout(5000);
// KeyStore
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("PATH/TO/.P12/file"), "P12password".toCharArray());
keyManagerFactory.init(keyStore, "P12password".toCharArray());
// ---
// TrustStore
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("PATH/TO/.JKS/file"), "JKSpassword".toCharArray());
trustManagerFactory.init(trustStore);
// ---
SSLContext context = SSLContext.getInstance("SSLv3");
context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
con.setSSLSocketFactory(context.getSocketFactory());
con.getContent();
CookieStore cookieJar = manager.getCookieStore();
List<HttpCookie> cookies = cookieJar.getCookies();
for (HttpCookie cookie: cookies) {
if (COOKIE_NAME.equals(cookie.getName())) {
COOKIE_VALUE = cookie.getValue();
return true;
}
}
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
In Mule ESB project I call authenticate in processor:
#Override
public MuleEvent process(MuleEvent event) throws MuleException {
MuleMessage message = event.getMessage();
try {
String payloadString = new String(message.getPayloadAsBytes());
LOGGER.info("\nMessage payload:\n" + payloadString + "\n\n");
String xml = extractXMLFromSOAPMessage(payloadString);
LOGGER.info("\nXML: " + xml + "\n\n");
if (authenticate()) {
//send request to server
}
} catch (Exception e) {
LOGGER.error("EXCEPTION: " + e.getMessage());
e.printStackTrace();
}
return event;
}
On this line con.getContent(); exception is raised: SSLException: Received fatal alert: illegal_parameter
This error also appeared in my JAVA project. But adding these parameters helped:
System.setProperty("jsse.enableSNIExtension", "false");
System.setProperty("com.sun.net.ssl.enableECC", "false");
Both JAVA and Mule are on the same machine.
Thanks in advance!
P.S. Sorry for my english (:
Solution is turned out to be very simple.
System.setProperty not working in Mule project.
So all JVM parameters can be configured in MULE_HOME/conf/wrapper.conf.
Here is my solution:
wrapper.java.additional.16=-Djsse.enableSNIExtension=FALSE
wrapper.java.additional.17=-Dcom.sun.net.ssl.enableECC=FALSE
Thank to Vijay Pande.

Have you tried setting JVM parameters as described in mule documentation.

Related

HTTP transport error: java.net.ConnectException: Connection timed out: connect

Here, I am creating client project and trying to call/consume soap webservice.
But every time getting same error
HTTP transport error: java.net.ConnectException: Connection timed out: connect
It is very secured and vendor provided certificate and password to consume it.
I am little bit confused with the SSL configuration. Please check following code and suggest right way to do all SSL configuration if its wrong.
systemProps.setProperty("javax.net.ssl.keyStore", new File("Path of Certificate").getAbsolutePath());
systemProps.setProperty("javax.net.ssl.keyStorePassword", "***");
systemProps.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
systemProps.setProperty("java.net.useSystemProxies", "true");
String provider = System.getProperty("javax.net.ssl.keyStoreProvider");
String keyStoreType = systemProps.getProperty("javax.net.ssl.keyStoreType");
KeyStore ks = null;
if (provider != null) {
ks = KeyStore.getInstance(keyStoreType, provider);
} else {
ks = KeyStore.getInstance(keyStoreType);
}
InputStream ksis = null;
String keystorePath = systemProps.getProperty("javax.net.ssl.keyStore");
String keystorePassword = systemProps.getProperty("javax.net.ssl.keyStorePassword");
if (keystorePath != null && !"NONE".equals(keystorePath)) {
ksis = new FileInputStream(keystorePath);
}
try {
ks.load(ksis, keystorePassword.toCharArray());
} finally {
if (ksis != null) { ksis.close(); }
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, keystorePassword.toCharArray());
// Note that there is no property for the key password itself, which may be different.
// We're using the keystore password too.
SSLContext sc = SSLContext.getInstance("SSLv3");
sc.init(kmf.getKeyManagers(), null, null);
((BindingProvider) ps).getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", sc.getSocketFactory());
Response response = ps.submitRequest(request); service call.
System.out.println(response.toString());
Here, I have not provided webservice URL anywhere and i dont know where to provide that in above code. Any suggestion if this might be the issue.

Basic Auth over HTTPS Java

I have HTTPS page calls working fine and I have HTTP Basic Auth working fine what I can not do is get Basic Auth running on a HTTPS connection.
I attach a code example but it doesn't work. I keep getting a 403. I have checked the username and password and it has been successful when testing it with the RESTClinet addon from Firefox.
Any help would be great. Thanks.
private static void getAPITest() throws MalformedURLException, IOException
{
try {
System.setProperty("javax.net.ssl.trustStore","/home/USER/CERTS/myTrustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "PASSWORD");
Authenticator myAuth = new Authenticator()
{
#Override
protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication("USERNAME", "PASSWORD".toCharArray());
}
};
Authenticator.setDefault(myAuth);
String httpsURL = "https://someurlandapi.com";
URL myurl = new URL(httpsURL);
HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();
//con.setRequestProperty("Authorization", "Basic " + authString);
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
con.setRequestProperty("Accept", "application/json");
con.setRequestMethod("POST");
InputStream ins = con.getInputStream();
InputStreamReader isr = new InputStreamReader(ins);
BufferedReader in = new BufferedReader(isr);
String inputLine;
while ((inputLine = in.readLine()) != null)
{
System.out.println(inputLine);
}
ins.close();
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
it turns out don't have a space before the basic:
con.setRequestProperty("Authorization", "Basic " + authStringEnc);
and it needed:
conn.setRequestProperty("User-Agent", "Mozilla/5");
A quick note for anyone doing this if you are creating your own truststore you will need to add the sites/urls SSL certificate chain. In firefox you can click on the padlock > More information > security > view certificates. From there you can highlight the certificate export with chain it then add it to your truststore with the keytool:
keytool -import -file websitecertificate.pem -alias websitecert -keystore myTrustStore
I don't think PasswordAuthentication is doing what you want. But basic auth is really easy to handle yourself. If you're in Java8 it is simply Base64.getEncoder().encodeToString( ("USERNAME" + ":" + "PASSWORD").getBytes()).

Making Apache HttpClient 4.3 work with sslSocketFactory/HostnameVerifier

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();

Android - How to accept any certificates using HttpClient and passing a certificate at the same time

I have a scenario in which I must pass a certficate to my server, then the server sends me his certificate, which I must accept to access the server. I was using HttpURLConnection for this, with no problems.
However, I recently had a problem with HttpURLConnection. The code I was using retrieved an image from a HTTPS server. If the image was small (< 500kb), no problem whatsoever occured. However, with larger images I got this:
javax.net.ssl.SSLProtocolException: Read error: ssl=0x3c97e8: Failure in SSL library, usually a protocol error
I was reading about it on the Internet, and many people said that using HttpClient instead of HttpURLConnection was the way to go (an example is this site http://soan.tistory.com/62 , think that is written in korean, I can't read it but that's what I think it says).
This is my old code, using URLConnection:
public static URLConnection CreateFromP12(String uri, String keyFilePath,
String keyPass, TrustManager[] trustPolicy, HostnameVerifier hv) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyStore keyStore = KeyStore.getInstance("PKCS12");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
keyStore.load(new FileInputStream(keyFilePath),
keyPass.toCharArray());
kmf.init(keyStore, keyPass.toCharArray());
sslContext.init(kmf.getKeyManagers(), trustPolicy, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext
.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
} catch (Exception ex) {
return null;
}
URL url;
URLConnection conn;
try {
url = new URL(uri);
conn = url.openConnection();
} catch (MalformedURLException e) {
return null;
} catch (IOException e) {
return null;
}
return conn;
}
And this is the new one, using HttpClient:
public class HttpC2Connection {
public static HttpEntity CreateHttpEntityFromP12(String uri,
String keyFilePath, String keyPass) throws Exception {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream(keyFilePath), keyPass.toCharArray());
SSLSocketFactory sf = new MySSLSocketFactory(keyStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params,
registry);
HttpClient httpclient = new DefaultHttpClient(ccm, params);
HttpGet httpget = new HttpGet(uri);
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
return entity;
}
But now, using HttpClient, my server returns me an error saying that I must pass a certificate, so I guess that
SSLSocketFactory sf = new MySSLSocketFactory(keyStore);
isn't loading my certificate.
So, how can I do the following two things at the same time:
1.) Pass a certificate to my server;
2.) Accept any certificate from my server
Using the HttpClient class?
PS: I'm using Android 3.0
Thanks
The following code disables SSL certificate checking for any new instances of HttpsUrlConnection:
https://gist.github.com/aembleton/889392
/**
* Disables the SSL certificate checking for new instances of {#link HttpsURLConnection} This has been created to
* aid testing on a local box, not for use on production.
*/
private static void disableSSLCertificateChecking() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
#Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
} };
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
Don't just accept any certificates. Don't use home-made SSLSocketFactory's that compromise security. Use the SSLSocketFactory from the SDK, and pass both a trust store (containing the server certificate or the CA certificate that issued it) and a keystore (containing your client certificate and private key). You can use this constructor to achieve this, the JavaDoc has details on how to create the key stores.

Android: Problem exchanging messages with SSL

I have been trying to get a client to communicate with a server securely through SSL. I created my own self-signed certificates and it seems like that the client can connect to the server using the certificates, but the client never seems to be getting the response from the server. I tried printing the content-length which returns -1 and the actual content seems to be an empty string, although a simple HTML 'hello world' is expected.
What am I doing wrong?
Server:
public class SSLServer {
public static void main(String[] args) {
String ksName = "key.jks";
char ksPass[] = "password".toCharArray();
char ctPass[] = "password".toCharArray();
try {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(ksName), ksPass);
KeyManagerFactory kmf =
KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, ctPass);
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);
SSLServerSocketFactory ssf = sc.getServerSocketFactory();
SSLServerSocket s
= (SSLServerSocket) ssf.createServerSocket(8888);
System.out.println("Server started:");
// Listening to the port
SSLSocket c = (SSLSocket) s.accept();
BufferedWriter w = new BufferedWriter(
new OutputStreamWriter(c.getOutputStream()));
w.write("HTTP/1.0 200 OK");
w.write("Content-Type: text/html");
w.write("<html><body>Hello world!</body></html>");
w.flush();
w.close();
c.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Client:
public class TestSSLActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://192.168.15.195:8888");
// Execute the GET call and obtain the response
HttpResponse getResponse;
try {
getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
Log.i("Connection",responseEntity.getContentLength()+"");
BufferedReader reader = new BufferedReader(new InputStreamReader(responseEntity.getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null;) {
builder.append(line).append("\n");
}
Log.i("Connection","build: "+builder.toString());
} catch (Exception e) {
Log.i("Connection",e.getMessage());
}
}
Custom HTTP client:
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.key);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "password".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
You might want to change the server code to read the request from the client before sending the response. It could be that the client is blocking (and then timing out?) waiting for the server to read the request.

Categories

Resources