Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / Security / April 2004

Tip: Looking for answers? Try searching our database.

Long delay using SSLSocketFactory

Thread view: 
Thomas Mantay - 14 Apr 2004 10:47 GMT
Hi all,

I need to do HTTPS requests from a WLS container through a proxy which
requires encoded username/password authentication. Therefore, I am
using an extension of SSLSocketFactory (part of SUN's JSSE), which
does the proxy authentication for me and the tunnel handshake as well.

Principally, the solution I thought of works. However, after starting
the WLS, the very first connection to the proxy takes more than two
minutes. Running the test once again, the connection to the proxy is
established almost instantaneously. Can anyone explain the long delay
in the first connection? It occurs when invoking method
SSLSocketFactory.getDefault() (see the below code snippet).

I scanned the port of the proxy and found no activity during the
delay. Neither, there are any outgoing TCP packages from the source
machine (where the JVM is running). So I assume that the delay is not
due to a network problem; it must be somewhere in the depths of the
JSSE classes.

Best regards,
Thomas Mantay

Here is the code I am using:

import java.net.*;
import java.io.*;
import java.security.*;
import sun.misc.BASE64Encoder;
import javax.net.*;
import javax.net.ssl.*;

public class SSLTunnelSocketFactory extends SSLSocketFactory {
   private String tunnelHost;
   private int tunnelPort;
   private SSLSocketFactory dfactory;
   private String tunnelPassword;
   private String tunnelUserName;
   private boolean socketConnected = false;
   private int falsecount = 0;

   /**
    *  Constructor for the SSLTunnelSocketFactory object
    *
    *@param  proxyHost      The url of the proxy host
    *@param  proxyPort      the port of the proxy
    *@param  proxyUserName  username for authenticating with the
proxy
    *@param  proxyPassword  password for authenticating with the
proxy
    */
   public SSLTunnelSocketFactory(String proxyHost, int proxyPort,
String proxyUserName, String proxyPassword) {
         NLUtil.ldebug("SSLTunnelSocketFactory", "Constructor", "creating
Socket Factory with password/username");
       tunnelHost = proxyHost;
       tunnelPort = proxyPort;
       tunnelUserName = proxyUserName;
       tunnelPassword = proxyPassword;
         NLUtil.ldebug("SSLTunnelSocketFactory", "Constructor", "before
getDefault()");

Here is the line that causes the delay:

       dfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
         NLUtil.ldebug("SSLTunnelSocketFactory", "Constructor", "after
getDefault()");
   }

   /**
    *  Gets the supportedCipherSuites attribute of the
SSLTunnelSocketFactory
    *  object
    *
    *@return    The supportedCipherSuites value
    */
   public String[] getSupportedCipherSuites() {
       return dfactory.getSupportedCipherSuites();
   }

   /**
    *  Gets the defaultCipherSuites attribute of the
SSLTunnelSocketFactory
    *  object
    *
    *@return    The defaultCipherSuites value
    */
   public String[] getDefaultCipherSuites() {
       return dfactory.getDefaultCipherSuites();
   }

   /**
    *  Gets the socketConnected attribute of the
SSLTunnelSocketFactory object
    *
    *@return    The socketConnected value
    */
   public synchronized boolean getSocketConnected() {
       return socketConnected;
   }

   /**
    *  Creates a new SSL Tunneled Socket
    *
    *@param  s                         Ignored
    *@param  host                      destination host
    *@param  port                      destination port
    *@param  autoClose                 wether to close the socket
automaticly
    *@return                           proxy tunneled socket
    *@exception  IOException           raised by an IO error
    *@exception  UnknownHostException  raised when the host is
unknown
    */
   public Socket createSocket(Socket s, String host, int port,
boolean autoClose)
            throws IOException, UnknownHostException {
       Socket tunnel = new Socket(tunnelHost, tunnelPort);
       doTunnelHandshake(tunnel, host, port);
       SSLSocket result = (SSLSocket) dfactory.createSocket(tunnel,
host, port, autoClose);
       result.addHandshakeCompletedListener(
           new HandshakeCompletedListener() {
               public void handshakeCompleted(HandshakeCompletedEvent
event) {
                         NLUtil.ldebug("SSLTunnelSocketFactory", "handshakeCompleted",
"Handshake Finished!");
                         NLUtil.ldebug("SSLTunnelSocketFactory", "handshakeCompleted",
"CipherSuite :" + event.getCipherSuite());
                         NLUtil.ldebug("SSLTunnelSocketFactory", "handshakeCompleted",
"SessionId: " + event.getSession());
                         NLUtil.ldebug("SSLTunnelSocketFactory", "handshakeCompleted",
"PeerHost: " + event.getSession().getPeerHost());
                   setSocketConnected(true);
               }
           });
       // thanks to David Lord in the java forums for figuring out
this line is the problem
       // result.startHandshake(); //this line is the bug which stops
Tip111 from working correctly
       return result;
   }

   /**
    *  Creates a new SSL Tunneled Socket
    *
    *@param  host                      destination host
    *@param  port                      destination port
    *@return                           tunneled SSL Socket
    *@exception  IOException           raised by IO error
    *@exception  UnknownHostException  raised when the host is
unknown
    */
   public Socket createSocket(String host, int port)
            throws IOException, UnknownHostException {
       return createSocket(null, host, port, true);
   }

   /**
    *  Creates a new SSL Tunneled Socket
    *
    *@param  host                      Destination Host
    *@param  port                      Destination Port
    *@param  clientHost                Ignored
    *@param  clientPort                Ignored
    *@return                           SSL Tunneled Socket
    *@exception  IOException           Raised when IO error occurs
    *@exception  UnknownHostException  Raised when the destination
host is
    *      unknown
    */
   public Socket createSocket(String host, int port, InetAddress
clientHost,
           int clientPort)
            throws IOException, UnknownHostException {
       return createSocket(null, host, port, true);
   }

   /**
    *  Creates a new SSL Tunneled Socket
    *
    *@param  host             destination host
    *@param  port             destination port
    *@return                  tunneled SSL Socket
    *@exception  IOException  raised when IO error occurs
    */
   public Socket createSocket(InetAddress host, int port)
            throws IOException {
       return createSocket(null, host.getHostName(), port, true);
   }

   /**
    *  Creates a new SSL Tunneled Socket
    *
    *@param  address          destination host
    *@param  port             destination port
    *@param  clientAddress    ignored
    *@param  clientPort       ignored
    *@return                  tunneled SSL Socket
    *@exception  IOException  raised when IO exception occurs
    */
   public Socket createSocket(InetAddress address, int port,
           InetAddress clientAddress, int clientPort)
            throws IOException {
       return createSocket(null, address.getHostName(), port, true);
   }

   /**
    *  Sets the socketConnected attribute of the
SSLTunnelSocketFactory object
    *
    *@param  b  The new socketConnected value
    */
   private synchronized void setSocketConnected(boolean b) {
       socketConnected = b;
   }

   /**
    *  Description of the Method
    *
    *@param  tunnel           tunnel socket
    *@param  host             destination host
    *@param  port             destination port
    *@exception  IOException  raised when an IO error occurs
    */
   private void doTunnelHandshake(Socket tunnel, String host, int
port) throws IOException {
         NLUtil.ldebug("SSLTunnelSocketFactory", "doTunnelHandshake",
"doTunnelHandshake start");
       OutputStream out = tunnel.getOutputStream();
       //generate connection string
       String msg = "CONNECT " + host + ":" + port + " HTTP/1.0\n"
                + "User-Agent: "
                + sun.net.www.protocol.http.HttpURLConnection.userAgent;
       if (!tunnelUserName.equals("") && !tunnelPassword.equals(""))
{
                NLUtil.ldebug("SSLTunnelSocketFactory", "doTunnelHandshake",
"Using proxy authencation with username '" + tunnelUserName + "' and
password '" + tunnelPassword + "'.");
           //add basic authentication header for the proxy
                sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
           String encodedPassword = enc.encode((tunnelUserName + ":"
+ tunnelPassword).getBytes());
           msg = msg + "\nProxy-Authorization: Basic " +
encodedPassword;
       }
       msg = msg + "\nContent-Length: 0";
       msg = msg + "\nPragma: no-cache";

       msg = msg + "\r\n\r\n";

         NLUtil.ldebug("SSLTunnelSocketFactory", "doTunnelHandshake", "msg:
" + msg);

       byte b[];
       try {
           //we really do want ASCII7 as the http protocol doesnt
change with locale
           b = msg.getBytes("ASCII7");
       } catch (UnsupportedEncodingException ignored) {
           //If ASCII7 isn't there, something is seriously wrong!
           b = msg.getBytes();
       }
       out.write(b);
       out.flush();

       byte reply[] = new byte[200];
       int replyLen = 0;
       int newlinesSeen = 0;
       boolean headerDone = false;

       InputStream in = tunnel.getInputStream();
       boolean error = false;

       while (newlinesSeen < 2) {
           int i = in.read();
           if (i < 0) {
               throw new IOException("Unexpected EOF from Proxy");
           }
           if (i == '\n') {
               headerDone = true;
               ++newlinesSeen;
           } else
                   if (i != '\r') {
               newlinesSeen = 0;
               if (!headerDone && replyLen < reply.length) {
                   reply[replyLen++] = (byte) i;
               }
           }
       }

       //convert byte array to string
       String replyStr;
       try {
           replyStr = new String(reply, 0, replyLen, "ASCII7");
       } catch (UnsupportedEncodingException ignored) {
           replyStr = new String(reply, 0, replyLen);
       }

       //we check for connection established because our proxy
returns http/1.1 instead of 1.0
       if (replyStr.toLowerCase().indexOf("200 connection
established") == -1) {
                NLUtil.ldebug("SSLTunnelSocketFactory", "doTunnelHandshake",
"replyStr: " + replyStr);
           System.err.println(replyStr);
           throw new IOException("Unable to tunnel through " +
tunnelHost + ":" + tunnelPort + ". Proxy returns\"" + replyStr +
"\"");
       }
       //tunneling hanshake was successful
   }
   
}
Roedy Green - 15 Apr 2004 05:01 GMT
>Can anyone explain the long delay
>in the first connection?

I can't tell you precisely, but chances are something is timing out
waiting for a response, then tries another approach that does work.

You might speed it up by fiddling with any sort of configurable
timeout length.

--
Canadian Mind Products, Roedy Green.
Coaching, problem solving, economical contract programming.
See http://mindprod.com/jgloss/jgloss.html for The Java Glossary.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.