Connexion Java Client au Serveur HTTPS via proxy
Je suis entrain de developper un client java qui se connecte a une servlet (web service) en HTTPS / SSL , mon application passe par le proxy.
Voilà le code :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
package sslproject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
public class HtpsConnection {
public static String urlHost ="https://X.X.X.X:443/PathServle";
public static void main (String[] args) throws IOException {
System.out.println(getPage(urlHost).toString());
}
public static StringBuffer getPage(String urlString)
{
public static String proxyPwd = "proxyPWD";
public static String proxyUser = "proxyUSER";
public static String proxyHost = "proxyIP";
public static int proxyPort = port_proxy;
System.getProperties().put("javax.net.debug", "ssl" );
System.getProperties().put("https.proxySet", "true");
System.getProperties().put("https.proxyHost", proxyHost);
System.getProperties().put("https.proxyPort", proxyPort);
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public boolean checkClientTrusted(java.security.cert.X509Certificate[] chain){
return true;
}
public boolean isServerTrusted(java.security.cert.X509Certificate[] chain){
return true;
}
public boolean isClientTrusted(java.security.cert.X509Certificate[] chain){
return true;
}
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
}
};
try
{
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
catch(NoSuchAlgorithmException nsae)
{}
catch(KeyManagementException kme)
{
kme.printStackTrace();
}
try
{
HttpsURLConnection connec = null;
URL url = new URL(urlString);
connec = (HttpsURLConnection)url.openConnection();
connec.setDoInput(true);
connec.setUseCaches(false);
String authentication = proxyUser + ":" + proxyPwd;
String encodedPassword = "Basic " + new sun.misc.BASE64Encoder().encode(authentication.getBytes());
connec.setRequestProperty("Proxy-Authorization", encodedPassword);
//connec.setRequestProperty("X-TestHeader", "value");
connec.setRequestMethod("POST");
connec.setDoOutput(true);
String msg;
msg= "---"+"\r\n";
int statusCode = connec.getResponseCode();
//System.err.println("Certificats --->"+connec.getServerCertificates());
System.err.println("HEADER --->"+connec.getHeaderFields());
StringBuffer pageContents = new StringBuffer();
if(statusCode==HttpsURLConnection.HTTP_OK)
{
System.err.println("Connected ...!");
BufferedReader in = new BufferedReader(new InputStreamReader(connec.getInputStream()));
PrintWriter out = new PrintWriter(connec.getOutputStream(), true );
out.println(msg);
String curLine = in.readLine();
while(curLine!=null)
{
pageContents.append(curLine);
curLine = in.readLine();
}
}
return pageContents;
}
catch(MalformedURLException mue)
{
mue.printStackTrace();
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
return null;
}
} |
Voilà la réponse :
Citation:
HEADER --->{null=[HTTP/1.1 500 Internal Server Error], Content-Length=[101], Connection=[Close], Date=[Fri, 01 Dec 2006 11:38:11 GMT], Content-Type=[text/html]}
Sou unix/linx j'ai executer la command wget voilà le résultat :
Citation:
root@becane:~#wget X.X.X.X 443
...
Connecting to X.X.X.X:443... connected.
ERROR: Certificate verification error for X.X.X.X : unable to get local issuer certificate
ERROR: certificate common name `X.X.X.X' doesn't match requested host name `X.X.X.X:443'.
To connect to X.X.X.X:443 insecurely, use `--no-check-certificate'.
Unable to establish SSL connection.
--17:19:09--
http://443/
=> `index.html.1'
Resolving 443... 0.0.1.187
Connecting to 443|0.0.1.187|:80... failed: Invalid argument.
FINISHED --17:19:09--
Downloaded: 0 bytes in 0 files
Apparament j'ai un problème de certificat !
Comment utiliser le certificat du serveur https dans le code client java ?
Et comment fait on pour l'obtenir ?
Est ce que quelqu'un peut m'expliquer comment résoudre le problème est établir une connexion https ?
Des exemples de code sa serai sympa.
Merci d'avance
Une petite clarification...
Bonjour à tous !
Une petite clarification ne me semble pas inutile...
Il y a peut être des erreurs dans ce que je vais dire car il s'agit de mon interprétation personnelle.
J'ai toutefois eu l'occasion d'implémenter un client pour un web service à contacter via HTTPS (avec passage par un proxy) et mon code fonctionne très bien.
Lors d'une connexion SSL, deux scénarios sont envisageables.
Le premier scénario est une authentification unilatérale : le serveur vous envoie son certificat afin de vous prouver son idendité.
Le deuxième scénario est une authentification réciproque : le serveur vous envoie son certificat afin de vous prouver son idendité, vous envoyez votre propre certificat au serveur afin de lui prouver votre identité.
Le deuxième scénario est généralement appliqué pour restreindre l'accès au web service.
Notez que le certificat du serveur est généralement délivré par une autorité de certification (CA), alors que votre propre certificat vous est généralement délivré par l'entité responsable du web service, dans le cas d'une authentification réciproque.
Il est également important de souligner que, lorsque vous désirez établir une connexion SSL, deux fichiers sont importants :
Le keystore n'est utile que dans le cas d'une authentification réciproque. Il peut contenir plusieurs entrées. Chaque entrée est constituée d'un certificat ainsi que d'une clé privée qui vous sont propres.
Le trustore contient, quant à lui, les certificats des entités en lesquels vous avez choisi d'avoir confiance. Ainsi, une communication SSL avec un web service ne sera possible que si vous avez placé le certificat de ce service dans votre trustore (ou en créant un 'all trusting manager', comme nous le verrons ci-dessous).
Ca, c'est pour la théorie.
En pratique, JSSE (Java Secure Socket Extension) met à votre disposition deux classes très pratiques :
- KeyManager, un gestionnaire pour votre keystore
- TrustManager, un gestionnaire pour votre truststore
En ce qui concerne le trustManager, vous pouvez créer un 'all trusting manager', c'est-à-dire un manager qui accepte tous les certificats, grâce à la fonction suivante:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
public static TrustManager[] getAllTrustingTrustManager(){
return new TrustManager[]{
new X509TrustManager(){
public boolean checkClientTrusted(java.security.cert.X509Certificate[] chain){
return true;
}
public boolean isServerTrusted(java.security.cert.X509Certificate[] chain){
return true;
}
public boolean isClientTrusted(java.security.cert.X509Certificate[] chain){
return true;
}
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
}
};
} |
L'avantage de ce manager est qu'il vous permet de vous passer de trustore. L'inconvénient est qu'il n'est pas sécurisé.
Si une authentification réciproque est requise, vous devez construire votre keystore (il existe pour cela des outils) et créer ensuite un keyManager de la façon suivante :
Code:
1 2 3 4 5 6 7 8 9
|
char[] keystorepass = '<passwd>'.toCharArray(); //le mot de passe qui protège votre keystore
File keystoreFile = new File('<path>'); //le chemin d'accès à votre keystore
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(keystoreFile), keystorepass);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keystorepass);
KeyManager[] keyManager = keyManagerFactory.getKeyManagers(); //voici votre keyManager |
Ensuite, vous devez initialiser votre context SSL.
Pour une authentification réciproque :
Code:
1 2 3
|
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManager, trustManager, null); //vous spécifiez le keyManager et le trustManager créés plus haut |
Pour une authentification unilatérale:
Code:
1 2 3
|
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManager, null); //vous spécifiez le trustManager créé plus haut et un keyManager null |
Enfin, il ne vous reste plus qu'à ouvrir une connexion :
Code:
1 2 3
|
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection connection = (HttpsURLConnection)request.getUrl().openConnection(); |
Pour faire passer la connexion ci-dessus via un proxy, il suffit de définir l'adresse et le port du proxy de la façon suivante :
Code:
1 2 3
|
System.setProperty("http.proxyHost", "..."); //l'adresse du proxy
System.setProperty("http.proxyPort", "..."); //le port du proxy |
Voilà, c'est tout.
J'espère avoir été clair et que ceci vous aidera...
Au cas où une authentification proxy serait nécessaire...
J'ai oublié de parler d'un petit truc.
Lorsque vous désirez établir une connexion via un proxy, il se peut que ce proxy vous demande de vous authentifier (généralement via login/password).
Pour ce faire, utilisez la classe suivante :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public class SimpleAuthenticator extends Authenticator
{
private String username, password;
public SimpleAuthenticator(String username,String password) {
this.username = username;
this.password = password;
}
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username,password.toCharArray());
}
} |
Ensuite, juste avant d'établir votre connexion, au moment où vous définissez vos paramètres proxy (voir message précédent), faites
Code:
1 2
|
Authenticator.setDefault(new SimpleAuthenticator(username,password)); |
J'ai trouvé ce code à l'adresse suivante : http://www.developer.com/java/other/article.php/1551421.
Je ne l'ai pas testé...
A +
mise à jour URL keyTool IUI
Pour info, le nouveau lien est
keyTool IUI
keyTool IUI est désormais open-source, sous license GNU-LGPL