KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > fr > dyade > aaa > agent > HttpsNetwork


1 /*
2  * Copyright (C) 2005 - 2005 ScalAgent Distributed Technologies
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  * USA.
18  *
19  * Initial developer(s): ScalAgent Distributed Technologies
20  * Contributor(s):
21  */

22 package fr.dyade.aaa.agent;
23
24 import java.io.*;
25 import java.net.*;
26 import javax.net.ssl.*;
27 import java.security.KeyStore JavaDoc;
28 import javax.security.cert.X509Certificate;
29 import java.util.Vector JavaDoc;
30
31 import org.objectweb.util.monolog.api.BasicLevel;
32 import org.objectweb.util.monolog.api.Logger;
33
34 import fr.dyade.aaa.util.*;
35
36 /**
37  * <tt>HttpNetwork</tt> is a specialization of <tt>HttpNetwork</tt>
38  * for SSL.
39  */

40 public final class HttpsNetwork extends HttpNetwork {
41   /**
42    * Name of property that allow to fix the keystore's password:
43    * "HttpsNetwork.pass". By default the password is "changeit".
44    * This property can be fixed either from <code>java</code> launching
45    * command (-Dname=value), or by in <code>a3servers.xml</code> configuration
46    * file (property element).
47    */

48   public final static String JavaDoc PASS = "HttpsNetwork.pass";
49   /**
50    * Name of property that allow to fix the keystore's pathname:
51    * "HttpsNetwork.keyfile". By default the key file is ".keystore".
52    * This property can be fixed either from <code>java</code> launching
53    * command (-Dname=value), or by in <code>a3servers.xml</code> configuration
54    * file (property element).
55    */

56   public final static String JavaDoc KEYFILE = "HttpsNetwork.keyfile";
57
58   /**
59    *
60    */

61   SSLSocketFactory socketFactory = null;
62   /**
63    *
64    */

65   SSLServerSocketFactory serverSocketFactory = null;
66
67   public HttpsNetwork() throws Exception JavaDoc {
68     super();
69   }
70
71   SSLSocketFactory getSocketFactory() throws IOException {
72     if (socketFactory == null) {
73       try {
74         char[] pass = AgentServer.getProperty(PASS, "changeit").toCharArray();
75         String JavaDoc keyFile = AgentServer.getProperty(KEYFILE, ".keystore");
76  
77         KeyStore JavaDoc ks = KeyStore.getInstance("JKS");
78         ks.load(new FileInputStream(keyFile), pass);
79
80 // KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
81
// kmf.init(ks, pass);
82

83         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
84         tmf.init(ks);
85
86         SSLContext ctx = SSLContext.getInstance("TLS");
87         ctx.init(null, tmf.getTrustManagers(), null);
88  
89         socketFactory = ctx.getSocketFactory();
90       } catch (IOException exc) {
91         throw exc;
92       } catch (Exception JavaDoc exc) {
93         logmon.log(BasicLevel.ERROR,
94                    this.getName() + ", cannot initialize SSLSocketFactory", exc);
95         throw new IOException(exc.getMessage());
96       }
97     }
98     return socketFactory;
99   }
100
101   SSLServerSocketFactory getServerSocketFactory() throws IOException {
102     if (serverSocketFactory == null) {
103       try {
104         char[] pass = AgentServer.getProperty(PASS, "changeit").toCharArray();
105         String JavaDoc keyFile = AgentServer.getProperty(KEYFILE, ".keystore");
106  
107         KeyStore JavaDoc ks = KeyStore.getInstance("JKS");
108         ks.load(new FileInputStream(keyFile), pass);
109
110         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
111         kmf.init(ks, pass);
112
113         SSLContext ctx = SSLContext.getInstance("TLS");
114         ctx.init(kmf.getKeyManagers(), null, null);
115  
116         serverSocketFactory = ctx.getServerSocketFactory();
117       } catch (IOException exc) {
118         throw exc;
119       } catch (Exception JavaDoc exc) {
120         logmon.log(BasicLevel.ERROR,
121                    this.getName() + ", cannot initialize SSLServerSocketFactory", exc);
122         throw new IOException(exc.getMessage());
123       }
124     }
125     return serverSocketFactory;
126   }
127
128   /**
129    * This method creates and returns a SSL server socket which uses all
130    * network interfaces on the host, and is bound to the specified port.
131    *
132    * @param port the port to listen to.
133    * @return a SSL server socket bound to the specified port.
134    *
135    * @exception IOException for networking errors
136    */

137   ServerSocket createServerSocket(int port) throws IOException {
138     ServerSocket serverSocket = null;
139     serverSocket = getServerSocketFactory().createServerSocket(port, backlog);
140     ((SSLServerSocket) serverSocket).setNeedClientAuth(false);
141
142     return serverSocket;
143   }
144
145   /**
146    * This method creates and returns a SSL socket connected to a ServerSocket
147    * at the specified network address and port.
148    *
149    * @param host the server host.
150    * @param port the server port.
151    * @return a socket connected to a ServerSocket at the specified
152    * network address and port.
153    *
154    * @exception IOException if the connection can't be established
155    */

156   Socket createSocket(InetAddress host, int port) throws IOException {
157     if (host == null)
158       throw new UnknownHostException();
159
160     return getSocketFactory().createSocket(host, port);
161   }
162
163   /**
164    * This method creates a tunnelling socket if a proxy is used.
165    *
166    * @param host the server host.
167    * @param port the server port.
168    * @param proxy the proxy host.
169    * @param proxyport the proxy port.
170    * @return a socket connected to a ServerSocket at the specified
171    * network address and port.
172    *
173    * @exception IOException if the connection can't be established
174    */

175   Socket createTunnelSocket(InetAddress host, int port,
176                             InetAddress proxy, int proxyport) throws IOException {
177 // SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
178

179     // Set up a socket to do tunneling through the proxy.
180
// Start it off as a regular socket, then layer SSL over the top of it.
181
Socket tunnel = new Socket(proxy, proxyport);
182     doTunnelHandshake(tunnel, host, port);
183
184     // Ok, let's overlay the tunnel socket with SSL.
185
SSLSocket socket =
186       (SSLSocket) getSocketFactory().createSocket(tunnel,host.getHostName(), port, true);
187     // register a callback for handshaking completion event
188
socket.addHandshakeCompletedListener(
189       new HandshakeCompletedListener() {
190         public void handshakeCompleted(HandshakeCompletedEvent event) {
191         }
192       });
193
194     return socket;
195   }
196
197   private void doTunnelHandshake(Socket tunnel, InetAddress host, int port)
198     throws IOException {
199     OutputStream out = tunnel.getOutputStream();
200     String JavaDoc msg = "CONNECT " + host.getHostName() + ":" + port + " HTTP/1.0\n"
201       + "User-Agent: "
202       + sun.net.www.protocol.http.HttpURLConnection.userAgent
203       + "\r\n\r\n";
204     byte b[];
205     try {
206       // We really do want ASCII7 -- the http protocol doesn't change
207
// with locale.
208
b = msg.getBytes("ASCII7");
209     } catch (UnsupportedEncodingException ignored) {
210       // If ASCII7 isn't there, something serious is wrong, but
211
// Paranoia Is Good (tm)
212
b = msg.getBytes();
213     }
214     out.write(b);
215     out.flush();
216
217     // We need to store the reply so we can create a detailed
218
// error message to the user.
219
byte reply[] = new byte[200];
220     int replyLen = 0;
221     int newlinesSeen = 0;
222     boolean headerDone = false; /* Done on first newline */
223
224     InputStream in = tunnel.getInputStream();
225     boolean error = false;
226
227     while (newlinesSeen < 2) {
228       int i = in.read();
229       if (i < 0) {
230         throw new IOException("Unexpected EOF from proxy");
231       }
232       if (i == '\n') {
233         headerDone = true;
234         ++newlinesSeen;
235       } else if (i != '\r') {
236         newlinesSeen = 0;
237         if (!headerDone && replyLen < reply.length) {
238           reply[replyLen++] = (byte) i;
239         }
240       }
241     }
242
243     // Converting the byte array to a string is slightly wasteful
244
// in the case where the connection was successful, but it's
245
// insignificant compared to the network overhead.
246
String JavaDoc replyStr;
247     try {
248       replyStr = new String JavaDoc(reply, 0, replyLen, "ASCII7");
249     } catch (UnsupportedEncodingException ignored) {
250       replyStr = new String JavaDoc(reply, 0, replyLen);
251     }
252
253     /* We asked for HTTP/1.0, so we should get that back */
254     if (! (replyStr.startsWith("HTTP/1.0 200") ||
255           (replyStr.startsWith("HTTP/1.1 200")))) {
256       throw new IOException("Unable to tunnel , proxy returns \"" + replyStr + "\"");
257     }
258
259     // tunneling Handshake was successful!
260
}
261 }
262
263
Popular Tags