Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
https.ProxyHost and https.ProxyPort system properties. The tunneling code in JSSE checks for "HTTP 1.0" in the proxy's response. If your proxy, like many, returns
"HTTP 1.1", you will get an IOException. In this case, you need to implement your own HTTPS tunneling protocol. In this article, I will show you how to create a secure socket that tunnels through the firewall, and pass it to the HTTPS
stream handler to open HTTPS URLs using the URLConnection class.
The first step to creating your secure socket is to open the tunneling socket to the proxy port. The code needed to do this
proxy handshaking can be found in the sample code SSLClientSocketWithTunneling.java that comes with the JSSE distribution. First, a normal socket is created that connects to the proxy port on the proxy host
(line 65). After the socket is created, it is passed to the doTunnelHandshake() method where the proxy's tunneling protocol is called:
54 SSLSocketFactory factory =
55 (SSLSocketFactory)SSLSocketFactory.getDefault();
56
57 /*
58 * Set up a socket to do tunneling through the proxy.
59 * Start it off as a regular socket, then layer SSL
60 * over the top of it.
61 */
62 tunnelHost = System.getProperty("https.proxyHost");
63 tunnelPort = Integer.getInteger("https.proxyPort").intValue();
64
65 Socket tunnel = new Socket(tunnelHost, tunnelPort);
66 doTunnelHandshake(tunnel, host, port);
In doTunnelHandshake(), an http "CONNECT" command is sent to the proxy, with the secure site's hostname and port number as the parameters (line 161). In the original
tunneling code on line 206 in JSSE, it then checks for "HTTP/1.0 200" in the proxy's reply. If your organization's proxy replies
with "HTTP 1.1", an IOException will be thrown. To get around this, the code here checks for the reply "200 Connection Established", which indicates that
tunneling is successful (line 207). You can modify the code to check for the expected corresponding response from your proxy:
139 private void doTunnelHandshake(Socket tunnel, String host, int port)
140 throws IOException
141 {
142 OutputStream out = tunnel.getOutputStream();
143 String msg = "CONNECT " + host + ":" + port + " HTTP/1.0\n"
144 + "User-Agent: "
145 + sun.net.www.protocol.http.HttpURLConnection.userAgent
146 + "\r\n\r\n";
147 byte b[];
148 try {
149 /*
150 * We really do want ASCII7 -- the http protocol doesn't change
151 * with locale.
152 */
153 b = msg.getBytes("ASCII7");
154 } catch (UnsupportedEncodingException ignored) {
155 /*
156 * If ASCII7 isn't there, something serious is wrong, but
157 * Paranoia Is Good (tm)
158 */
159 b = msg.getBytes();
160 }
161 out.write(b);
162 out.flush();
163
164 /*
165 * We need to store the reply so we can create a detailed
166 * error message to the user.
167 */
168 byte reply[] = new byte[200];
169 int replyLen = 0;
170 int newlinesSeen = 0;
171 boolean headerDone = false; /* Done on first newline */
172
173 InputStream in = tunnel.getInputStream();
174 boolean error = false;
175
176 while (newlinesSeen < 2) {
177 int i = in.read();
178 if (i < 0) {
179 throw new IOException("Unexpected EOF from proxy");
180 }
181 if (i == '\n') {
182 headerDone = true;
183 ++newlinesSeen;
184 } else if (i != '\r') {
185 newlinesSeen = 0;
186 if (!headerDone && replyLen < reply.length) {
187 reply[replyLen++] = (byte) i;
188 }
189 }
190 }
191
192 /*
193 * Converting the byte array to a string is slightly wasteful
194 * in the case where the connection was successful, but it's
195 * insignificant compared to the network overhead.
196 */
197 String replyStr;
198 try {
199 replyStr = new String(reply, 0, replyLen, "ASCII7");
200 } catch (UnsupportedEncodingException ignored) {
201 replyStr = new String(reply, 0, replyLen);
202 }
203
204 /* We check for Connection Established because our proxy returns
205 * HTTP/1.1 instead of 1.0 */
206 //if (!replyStr.startsWith("HTTP/1.0 200")) {
207 if(replyStr.toLowerCase().indexOf(
208 "200 connection established") == -1){
209 throw new IOException("Unable to tunnel through "
210 + tunnelHost + ":" + tunnelPort
211 + ". Proxy returns \"" + replyStr + "\"");
212 }
213
214 /* tunneling Handshake was successful! */
215 }
After you have successfully created the tunneling socket, you overlay it with the SSL socket. Again, this is not difficult to do:
54 SSLSocketFactory factory =
55 (SSLSocketFactory)SSLSocketFactory.getDefault();
56
57 /*
58 * Set up a socket to do tunneling through the proxy.
59 * Start it off as a regular socket, then layer SSL
60 * over the top of it.
61 */
62 tunnelHost = System.getProperty("https.proxyHost");
63 tunnelPort = Integer.getInteger("https.proxyPort").intValue();
64
65 Socket tunnel = new Socket(tunnelHost, tunnelPort);
66 doTunnelHandshake(tunnel, host, port);
67
68 /*
69 * Ok, let's overlay the tunnel socket with SSL.
70 */
71 SSLSocket socket =
72 (SSLSocket)factory.createSocket(tunnel, host, port, true);
73
74 /*
75 * register a callback for handshaking completion event
76 */
77 socket.addHandshakeCompletedListener(
78 new HandshakeCompletedListener() {
79 public void handshakeCompleted(
80 HandshakeCompletedEvent event) {
81 System.out.println("Handshake finished!");
82 System.out.println(
83 "\t CipherSuite:" + event.getCipherSuite());
84 System.out.println(
85 "\t SessionId " + event.getSession());
86 System.out.println(
87 "\t PeerHost " + event.getSession().getPeerHost());
88 }
89 }
90 );
The code had called the SSLSocketFactory's getDefault() method earlier to get an instance of the SSLSocketFactory (line 54, repeated above). Next, it passes the tunneling socket that was created in the previous step to the createSocket() method of the SSLSocketFactory. The createSocket() method returns an SSLSocket that is connected to the destination host and port via the proxy tunnel. You can optionally add a HandshakeCompletedListener to the socket if you wish to be informed when the SSL handshaking is completed.
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq