Tengo 2 aplicaciones, una es Servlet/Tomcat Server y la otra es una aplicación de Android.Android: conexión HTTPS (SSL) usando HttpsURLConnection
Quiero utilizar HttpURLConnection para enviar y recibir XML entre ambos.
Código:
private String sendPostRequest(String requeststring) {
DataInputStream dis = null;
StringBuffer messagebuffer = new StringBuffer();
HttpURLConnection urlConnection = null;
try {
URL url = new URL(this.getServerURL());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
out.write(requeststring.getBytes());
out.flush();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
dis = new DataInputStream(in);
int ch;
long len = urlConnection.getContentLength();
if (len != -1) {
for (int i = 0; i < len; i++)
if ((ch = dis.read()) != -1) {
messagebuffer.append((char) ch);
}
} else {
while ((ch = dis.read()) != -1)
messagebuffer.append((char) ch);
}
dis.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
urlConnection.disconnect();
}
return messagebuffer.toString();
}
Ahora, tengo que usar SSL para enviar los XMLs para la seguridad.
Primero, utilizo Java Keytool para generar el archivo .keystore.
Keytool -keygen -alias tomcat -keyalg RSA
Entonces poner el código XML en el archivo server.xml de Tomcat para utilizar SSL
<Connector
port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="c:/Documents and Settings/MyUser/.keystore"
keystorePass="password"
clientAuth="false" sslProtocol="TLS"
/>
Entonces, lo cambio por el HttpURLConnection HttpsURLConnection
private String sendPostRequest(String requeststring) {
DataInputStream dis = null;
StringBuffer messagebuffer = new StringBuffer();
HttpURLConnection urlConnection = null;
//Conexion por HTTPS
HttpsURLConnection urlHttpsConnection = null;
try {
URL url = new URL(this.getServerURL());
//urlConnection = (HttpURLConnection) url.openConnection();
//Si necesito usar HTTPS
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
//Creo la Conexion
urlHttpsConnection = (HttpsURLConnection) url.openConnection();
//Seteo la verificacion para que NO verifique nada!!
urlHttpsConnection.setHostnameVerifier(DO_NOT_VERIFY);
//Asigno a la otra variable para usar simpre la mism
urlConnection = urlHttpsConnection;
} else {
urlConnection = (HttpURLConnection) url.openConnection();
}
//Do the same like up
y añadir un trustAllHosts método para confiar en cada servidor (no verificar ningún certificado)
private static void trustAllHosts() {
X509TrustManager easyTrustManager = new X509TrustManager() {
public void checkClientTrusted(
X509Certificate[] chain,
String authType) throws CertificateException {
// Oh, I am easy!
}
public void checkServerTrusted(
X509Certificate[] chain,
String authType) throws CertificateException {
// Oh, I am easy!
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
Esos cambios funcionaron muy bien, pero no quiero confiar en cada servidor. Quiero usar mi archivo de almacén de claves para validar la conexión y usar SSL de la manera correcta. He leído mucho en Internet y he realizado muchas pruebas, pero no puedo entender lo que tengo que hacer y cómo hacerlo.
¿Alguien me puede ayudar?
Muchas gracias
Lo siento por mi mala Inglés
------------------------- ACTUALIZACIÓN 2011/08/24 ------------------------------------------------ -
Bueno, todavía estoy trabajando en esto. Hice un nuevo método para establecer el almacén de claves, InputStream, etc
El método es el siguiente:
private static void trustIFNetServer() {
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
String keyPassword = "password";
ks.load(in, keyPassword.toCharArray());
in.close();
tmf.init(ks);
TrustManager[] tms = tmf.getTrustManagers();
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, tms, new java.security.SecureRandom());
} catch (Exception e) {
e.printStackTrace();
}
}
Primero tuve un montón de problemas con la clave y el certificado, pero ahora se está trabajando (Creo que sí)
Mi problema en este momento es una excepción TimeOut. No sé por qué se genera. Creo que es algo con la escritura de datos, pero no puedo resolverlo todavía.
¿Alguna idea?
¿Está utilizando un certificado firmado por una autoridad de certificación conocido o está utilizando un certificado autofirmado? –