You are viewing a plain text version of this content. The canonical link for it is here.
Posted to soap-user@xml.apache.org by David Wall <dw...@Yozons.com> on 2001/10/30 05:54:49 UTC

BUG FIX - Soap 2.2 SSL via proxy

How do I post code that seems to fix a bug in Apache SOAP 2.2 with respect to using SSL through a proxy server?

While I don't purport to be an Apache SOAP programming expert, I'll share the code here in the hopes that it will make it into the next iteration.  Of course, I'm sure it can be made nicer since I was just trying to hack out a fix to keep me moving forward.  There's no doubt a more elegant way...  For now, I'm just using my modified JAR, but I'd much prefer to have the "blessed version" in the next release.

Thanks,
David



+++

In org.apache.soap.util.net.HTTPUtils (note that I've just branch the code -- again -- based on whether a proxy server was specified or not, so that if a proxy was specified, then it is passed along to the SSLUtils code)


  private static Socket buildSocket(URL url, int targetPort,
                                    String httpProxyHost, int httpProxyPort)
     throws Exception {
      Socket s = null;
      String host = null;
      int port;

      if (httpProxyHost == null) {
          host = url.getHost();
          port = targetPort;
      } else {
          host = httpProxyHost;
          port = httpProxyPort;
      }

      if (url.getProtocol().equalsIgnoreCase("HTTPS")) {
       if ( httpProxyHost == null )
          {
            // Using reflection to avoid compile time dependencies
            Class SSLUtilsClass =
              Class.forName("org.apache.soap.util.net.SSLUtils");
            Class[] paramTypes = new Class[] {String.class, int.class};
            Method buildSSLSocket = SSLUtilsClass.getMethod(
              "buildSSLSocket", paramTypes);
            Object[] params = new Object[] {host, new Integer(port)};
            s = (Socket)buildSSLSocket.invoke(null, params);
       }
       else
       {
            // Using reflection to avoid compile time dependencies
            Class SSLUtilsClass =
              Class.forName("org.apache.soap.util.net.SSLUtils");
            Class[] paramTypes = new Class[] {String.class, int.class, String.class, int.class};
            Method buildSSLSocket = SSLUtilsClass.getMethod(
              "buildSSLSocket", paramTypes);
         Object[] params = new Object[] {host, new Integer(port), url.getHost(), new Integer(targetPort)};
            s = (Socket)buildSSLSocket.invoke(null, params);
       }
      } else {
          s = new Socket(host, port);
      }

      return s;
   }

+++

The new method added to org.apache.soap.util.net.SSLUtils differs because it it includes the parameters to the target host/port as well as the proxy host/port.  It creates a normal socket, does the proxy tunnel handshake with a CONNECT statement, then wraps that socket in an SSL socket and returns that.  Note that 'doTunnelHandshake()' was taken nearly "as is" from the sample code provided by Sun with JSSE 1.0.2.



 /** This method builds an SSL socket through a tunnel proxy, after auto-starting SSL */
 public static Socket buildSSLSocket(String proxyHost, int proxyPort, String targetHost, int targetPort)
  throws IOException, UnknownHostException
 {
     /*
      * Let's setup the SSLContext first, as there's a lot of
      * computations to be done.  If the socket were created
      * before the SSLContext, the server/proxy might timeout
      * waiting for the client to actually send something.
      */
     SSLSocketFactory factory =
  (SSLSocketFactory)SSLSocketFactory.getDefault();

     Socket tunnel = new Socket(proxyHost, proxyPort);
     doTunnelHandshake(tunnel, targetHost, targetPort);

     /*
      * Ok, let's overlay the tunnel socket with SSL.
      */
     SSLSocket sslSocket =
  (SSLSocket)factory.createSocket(tunnel, proxyHost, proxyPort, true);


 /*
      * Handshaking is started manually in this example because
      * PrintWriter catches all IOExceptions (including
      * SSLExceptions), sets an internal error flag, and then
      * returns without rethrowing the exception.
      *
      * Unfortunately, this means any error messages are lost,
      * which caused lots of confusion for others using this
      * code.  The only way to tell there was an error is to call
      * PrintWriter.checkError().
      */
     sslSocket.startHandshake();   
     
     return  sslSocket;  
     
  }

    /*
     * Tell our tunnel where we want to CONNECT, and look for the
     * right reply.  Throw IOException if anything goes wrong.
     */
    private static void doTunnelHandshake(Socket tunnel, String host, int port)
    throws IOException
    {
 OutputStream out = tunnel.getOutputStream();
 String msg = "CONNECT " + host + ":" + port + " HTTP/1.0\n"
       + "User-Agent: "
       + sun.net.www.protocol.http.HttpURLConnection.userAgent
       + "\r\n\r\n";
 byte b[];
 try {
     /*
      * We really do want ASCII7 -- the http protocol doesn't change
      * with locale.
      */
     b = msg.getBytes("ASCII7");
 } catch (UnsupportedEncodingException ignored) {
     /*
      * If ASCII7 isn't there, something serious is wrong, but
      * Paranoia Is Good (tm)
      */
     b = msg.getBytes();
 }
 out.write(b);
 out.flush();

 /*
  * We need to store the reply so we can create a detailed
  * error message to the user.
  */
 byte  reply[] = new byte[200];
 int  replyLen = 0;
 int  newlinesSeen = 0;
 boolean  headerDone = false; /* Done on first newline */

 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;
  }
     }
 }
 /*
  * Converting the byte array to a string is slightly wasteful
  * in the case where the connection was successful, but it's
  * insignificant compared to the network overhead.
  */
 String replyStr;
 try {
     replyStr = new String(reply, 0, replyLen, "ASCII7");
 } catch (UnsupportedEncodingException ignored) {
     replyStr = new String(reply, 0, replyLen);
 }

 /* We asked for HTTP/1.0, so we should get that back */
 if (!replyStr.startsWith("HTTP/1.0 200")) {
     throw new IOException("Unable to tunnel through "
      + "proxy returns \"" + replyStr + "\"");
 }

 /* tunneling Handshake was successful! */
    }


JAXM

Posted by David Wall <dw...@Yozons.com>.
Will Apache SOAP evolve to suport JAXM when it's ready?  Or will that be left to Axis?

David


JAXM

Posted by David Wall <dw...@Yozons.com>.
Will Apache SOAP evolve to suport JAXM when it's ready?  Or will that be left to Axis?

David