I haven't worked with SSL yet, but I did make a transport that uses HttpURLConnection. It shouldn't be too hard to modify it to use HttpsURLConnection. If you do:

call.setSOAPTransport(new AppletHTTPTransport()); It will use the post() method in AppletHTTPUtils, which can readily be souped up to allow HttpsURLConnections.


M.


At 01:11 PM 4/10/02 -0700, you wrote:

The breakpoint is never reached because Apache SOAP doesn't use the HttpsURLConnection class (or it's base classes) for communicaton but rather it's own set of classes working off of the lower level SSLSocket classes.

I'm pretty much stuck in the same boat so if anyone has had any success please pass on your findings.

-Joe

-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]
Sent: Wednesday, April 10, 2002 12:36 PM
To: [EMAIL PROTECTED]
Subject: How To Registering My Own Cert TrustManager for SOAP Call


How do I register my own X509TrustManager so that I can programmatically check the server cert in isServerTrusted() method for a SOAP call using apache SOAP 2.2. (My server has a self-signed cert)

When I code the following, https POSTS to the server, such as "https://localhost:8080/TestServlet", work fine because I registered the trust manager and it stops at my breakpoint in isServerTrusted()

// start code example

   class AnyHostnameVerifier implements HostnameVerifier {
      public boolean verify(
            java.lang.String urlHostname,
            java.lang.String certHostname) {
            return true;
      }
   }

   class AnyX509TrustManager implements X509TrustManager {
      public boolean isClientTrusted(java.security.cert.X509Certificate[]
chain) {
            return true;
      }
      public boolean isServerTrusted(java.security.cert.X509Certificate[]
chain) {
            return true;
      }
      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
      }
   }

   System.setProperty("java.protocol.handler.pkgs",
      "com.sun.net.ssl.internal.www.protocol");
   Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

   X509TrustManager tm = new AnyX509TrustManager();
   HostnameVerifier hm = new AnyHostnameVerifier();
   KeyManager[] km = null;
   TrustManager[] tma = { tm };
   SSLContext sc = SSLContext.getInstance("SSL");
   sc.init(km, tma, new java.security.SecureRandom());
   SSLSocketFactory sf1 = sc.getSocketFactory();

   HttpsURLConnection.setDefaultSSLSocketFactory(sf1);
   HttpsURLConnection.setDefaultHostnameVerifier(hm);

// end code example

BUT WHEN MAKING THE FOLLOWING SOAP CALL...

// start code example

   String targetObjectURI = "http://tempuri.org/Service";
   call.setMethodName("getName");
   call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
   call.setTargetObjectURI(targetObjectURI);
   call.setParams(new Vector());
   call.invoke( new URL(" https://localhost:8443/logon-example/servlet/rpcrouter"), "");

// end code example

IT FAILS WITH

main, SEND SSL v3.1 ALERT:  fatal, description = certificate_unknown main, WRITE:  SSL v3.1 Alert, length = 2 org.apache.soap.SOAPException, Error opening socket: null

AND THE BREAKPOINT IS NEVER REACHED IN MY REGISTERED TRUST-MANAGER
package com.childersoft.entity;

/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "SOAP" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2000, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */



import java.net.*;
import java.io.*;
import java.util.*;

import org.apache.soap.*;
import org.apache.soap.rpc.*;
import org.apache.soap.transport.*;
import org.apache.soap.util.mime.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
import java.lang.reflect.*;

/**
 * A bunch of utility stuff for doing HTTP things.
 * <p>
 * 2000/07/30 W. Cloetens     added Multipart Mime support
 *
 * @author Sanjiva Weerawarana ([EMAIL PROTECTED])
 * @author Matthew J. Duftler ([EMAIL PROTECTED])
 * @author Wouter Cloetens ([EMAIL PROTECTED])
 * @author Scott Nichol ([EMAIL PROTECTED])
 */
public class AppletHTTPUtils {
  public  static final int    DEFAULT_OUTPUT_BUFFER_SIZE = 512;


  /**
   * POST something to the given URL. The headers are put in as
   * HTTP headers, the content length is calculated and the content
   * byte array is sent as the POST content.
   *
   * @param url the url to post to
   * @param request the message
   * @param timeout the amount of time, in ms, to block on reading data
   * @param httpProxyHost the HTTP proxy host or null if no proxy
   * @param httpProxyPort the HTTP proxy port, if the proxy host is not null
   * @return the response message
   */
  public static TransportMessage post(URL url, TransportMessage request,
                                      int timeout,
                                      String httpProxyHost, int httpProxyPort)
      throws IllegalArgumentException, IOException, SOAPException {
    return post(url,
                request,
                timeout,
                httpProxyHost,
                httpProxyPort,
                DEFAULT_OUTPUT_BUFFER_SIZE);
  }

  /**
   * POST something to the given URL. The headers are put in as
   * HTTP headers, the content length is calculated and the content
   * byte array is sent as the POST content.
   *
   * @param url the url to post to
   * @param request the message
   * @param timeout the amount of time, in ms, to block on reading data
   * @param httpProxyHost the HTTP proxy host or null if no proxy
   * @param httpProxyPort the HTTP proxy port, if the proxy host is not null
   * @param outputBufferSize the size of the output buffer on the HTTP stream
   * @return the response message
   */
  public static TransportMessage post(URL url, TransportMessage request,
                                      int timeout,
                                      String httpProxyHost, int httpProxyPort,
                                      int outputBufferSize)
      throws IllegalArgumentException, IOException, SOAPException {
      /* Open the connection */
      OutputStream outStream = null;
      InputStream inStream = null;
      BufferedReader in = null;
      HttpURLConnection conn=(HttpURLConnection)url.openConnection();
      conn.setRequestMethod("POST");
      conn.setRequestProperty("SOAPAction","\"\"");
      conn.setRequestProperty("Content-type","text/xml;charset=utf-8");
      conn.setDoOutput(true);
      conn.setDoInput(true);
      outStream=conn.getOutputStream();

//Following code is if SOAP puts special headers in. If needed, use 
setRequestProperty() to
//do it.
      //      for (Enumeration e = request.getHeaderNames(); e.hasMoreElements(); ) {
//          Object key = e.nextElement();
//          headerbuf.append(key).append(": ")
//              .append(request.getHeader((String)key)).append("\r\n");
//      }
//      headerbuf.append("\r\n");


      BufferedOutputStream bOutStream = new BufferedOutputStream(outStream, 
outputBufferSize);
      request.writeTo(bOutStream);
      bOutStream.flush();
      outStream.flush();
      inStream=conn.getInputStream();

      /* Remember that no header is returned. Therefore, no need to parse the header
      out. If we want any elements of the header, we should get them directly. If we 
don't
      know all the headers, we can iterate through them. I don't think this is needed.
      */

      BufferedInputStream bInStream = new BufferedInputStream(inStream);
      /* Read the entire response (following the status line)
       * into a byte array. */
      ByteArrayDataSource ds = new ByteArrayDataSource(bInStream,
                          Constants.HEADERVAL_DEFAULT_CHARSET);

      /* Extract the headers, content type and content length. */
      byte[] bytes = ds.toByteArray();
      Hashtable respHeaders = new Hashtable();
      int respContentLength = -1;
      String respContentType = null;
      InputStream is = ds.getInputStream();
      respContentLength=conn.getHeaderFieldInt("Content-length",0);
      respContentType=conn.getHeaderField("Content-type");

      /* Construct the response object. */
      SOAPContext ctx;
      TransportMessage response;
      try {
          // Create response SOAPContext.
          ctx = new SOAPContext();
          // Read content.
          response = new TransportMessage(is, respContentLength,
                                          respContentType, ctx, respHeaders);
          // Extract envelope and SOAPContext
          response.read();
      } catch (MessagingException me) {
          throw new IllegalArgumentException("Error parsing response: " + me);
      }

      /* All done here! */
      bOutStream.close();
      outStream.close();
      bInStream.close();
      inStream.close();
      return response;
  }
}
package com.childersoft.entity;



/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "SOAP" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2000, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */


import java.io.*;
import java.net.*;
import java.util.*;
import org.w3c.dom.*;
import org.apache.soap.util.net.*;
import org.apache.soap.util.xml.*;
import org.apache.soap.util.mime.*;
import org.apache.soap.*;
import org.apache.soap.encoding.*;
import org.apache.soap.encoding.soapenc.Base64;
import org.apache.soap.transport.*;
import org.apache.soap.rpc.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;

/**
 * <code>SOAPHTTPConnection</code> is an implementation of the
 * <code>SOAPTransport</code> interface for <em>HTTP</em>.
 *
 * @author Matthew J. Duftler ([EMAIL PROTECTED])
 * @author Sanjiva Weerawarana ([EMAIL PROTECTED])
 * @author Wouter Cloetens ([EMAIL PROTECTED])
 * @author Scott Nichol ([EMAIL PROTECTED])
 */
public class AppletHTTPTransport implements SOAPTransport {
  private BufferedReader responseReader;
  private Hashtable responseHeaders;
  private SOAPContext responseSOAPContext;

  private String httpProxyHost;
  private int    httpProxyPort = 80;
  private int    timeout;
  private String userName;
  private String password;
  private String proxyUserName;
  private String proxyPassword;
  private boolean maintainSession = true;
  private String cookieHeader;
  private String cookieHeader2;
 private int    outputBufferSize = AppletHTTPUtils.DEFAULT_OUTPUT_BUFFER_SIZE;

  private static String encodeAuth(String userName, String password) {
    return Base64.encode((userName + ":" + password).getBytes());
  }

  /**
   * This method is used to request that an envelope be posted to the
   * given URL. The response (if any) must be gotten by calling the
   * receive() function.
   *
   * @param sendTo the URL to send the envelope to
   * @param action the SOAPAction header field value
   * @param headers any other header fields to go to as protocol headers
   * @param env the envelope to send
   * @param smr the XML<->Java type mapping registry (passed on)
   * @param ctx the request SOAPContext
   *
   * @exception SOAPException with appropriate reason code if problem
   */
  public void send (URL sendTo, String action, Hashtable headers,
                    Envelope env, SOAPMappingRegistry smr, SOAPContext ctx)
    throws SOAPException {
    try {
      String payload = null;
      if (env != null) {
        StringWriter payloadSW = new StringWriter ();
        env.marshall (payloadSW, smr, ctx);
        payload = payloadSW.toString ();
      }

      if (headers == null) {
        headers = new Hashtable ();
      }
      if (maintainSession) {
        // if there is saved cookie headers, put them in to the request
        if (cookieHeader2 != null) { // RFC 2965 header
          headers.put ("Cookie2", cookieHeader2);
        }
        if (cookieHeader != null) { // RFC 2109 header
          headers.put ("Cookie", cookieHeader);
        }
      }

      headers.put (Constants.HEADER_SOAP_ACTION,
                   (action != null) ? ('\"' + action + '\"') : "");
      if (userName != null) {
        // add the Authorization header for Basic authentication
        headers.put (Constants.HEADER_AUTHORIZATION,
                     "Basic " + encodeAuth(userName, password));

      }
      if (proxyUserName != null) {
        // add the Proxy-Authorization header for proxy authentication
        headers.put (Constants.HEADER_PROXY_AUTHORIZATION,
                    "Basic " + encodeAuth(proxyUserName, proxyPassword));
      }

      TransportMessage response;
      try
      {
        TransportMessage msg = new TransportMessage(payload, ctx, headers);
        msg.save();
        response = AppletHTTPUtils.post (sendTo, msg,
                                   timeout, httpProxyHost, httpProxyPort,
                                   outputBufferSize);
      } catch (MessagingException me) {
        throw new IOException ("Failed to encode mime multipart: " + me);
      } catch (UnsupportedEncodingException uee) {
        throw new IOException ("Failed to encode mime multipart: " + uee);
      }

      Reader envReader = response.getEnvelopeReader();
      if (envReader != null)
        responseReader = new BufferedReader(envReader);
      else
        responseReader = null;
      responseSOAPContext = response.getSOAPContext();
      responseHeaders = response.getHeaders();
      if (maintainSession) {
        // look for Set-Cookie2 and Set-Cookie headers and save them after
        // stripping everything after the ';' (i.e., ignore all cookie attrs).
        // Only update my state iff the header is there .. otherwise
        // leave the current
        String hdr;

        hdr = (String) responseHeaders.get ("Set-Cookie2");
        if (hdr != null) {
          cookieHeader2 = hdr;
          int index = cookieHeader2.indexOf (';');
          if (index != -1) {
            cookieHeader2 = cookieHeader2.substring (0, index);
          }
        }

        hdr = (String) responseHeaders.get ("Set-Cookie");
        if (hdr != null) {
          cookieHeader = hdr;
          int index = cookieHeader.indexOf (';');
          if (index != -1) {
            cookieHeader = cookieHeader.substring (0, index);
          }
        }
      }
    } catch (IllegalArgumentException e) {
      throw new SOAPException (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
    } catch (MessagingException e) {
      throw new SOAPException (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
    } catch (IOException e) {
      throw new SOAPException (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
    }
  }

  /**
   * Return a buffered reader to receive back the response to whatever
   * was sent to whatever.
   *
   * @return a reader to read the results from or null if that's not
   *         possible.
   */
  public BufferedReader receive () {
    return responseReader;
  }

  /**
   * Return access to headers generated by the protocol.
   *
   * @return a hashtable containing all the headers
   */
  public Hashtable getHeaders () {
    return responseHeaders;
  }

  /**
   * Return the SOAPContext associated with the response.
   *
   * @return response SOAPContext
   */
  public SOAPContext getResponseSOAPContext () {
    return responseSOAPContext;
  }
}



Reply via email to