Package org.w3c.jigsaw.https

Source Code of org.w3c.jigsaw.https.SSLAdapter

/**
* Copyright (c) 2000/2001 Thomas Kopp
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS 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 AUTHOR OR 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.
*/
// $Id: SSLAdapter.java,v 1.8 2007/02/11 18:41:12 ylafon Exp $

package org.w3c.jigsaw.https;

import java.io.ByteArrayInputStream;

import java.lang.reflect.Method;

import java.net.MalformedURLException;
import java.net.URL;

import java.util.StringTokenizer;

import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateFactory;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import org.w3c.jigsaw.daemon.ServerHandlerInitException;

import org.w3c.jigsaw.auth.AuthFilter;

import org.w3c.jigsaw.http.httpd;
import org.w3c.jigsaw.http.Client;
import org.w3c.jigsaw.http.Request;

import org.w3c.jigsaw.https.socket.SSLProperties;
import org.w3c.jigsaw.https.socket.SSLSocketClient;
import org.w3c.jigsaw.https.socket.SSLSocketClientFactory;

import org.w3c.tools.resources.ProtocolException;
import org.w3c.tools.resources.RequestInterface;

import org.w3c.util.ObservableProperties;

/**
* @author Thomas Kopp, Dialogika GmbH
* @version 1.1, 27 December 2000, 6 February 2004
*
* This class supplies a Jigsaw SSL daemon adapter
* for enabling Jigsaw https support in accordance with the JSSE API
* wrapping SSL features in order to solve multiple inheritance problems
*/
public class SSLAdapter {
   
    /**
     * The throwable initCause method via introspection
     * (for JDK backward compatibility)
     */
    private static final Method initCause;
   
    /**
     * The new style certificate support level indicator
     * (for JSSE backward compatibility)
     */
    private static final boolean supportsNewStyleCertificates;
   
    /**
     * The X509 factory for compatible certificate conversions
     */
    private static final CertificateFactory x509Factory;

    static {
        Class c = java.lang.Throwable.class;
        Class cp[] = { java.lang.Throwable.class };
        Method ic = null;
        try {
            ic = c.getMethod("initCause", cp);
        } catch (Exception ex) {
            ic = null;
        }
        finally {
            initCause = ic;
        }
        boolean supported = false;
        CertificateFactory fact = null;
        try {
            supported = (null !=
        javax.net.ssl.SSLSession.class.getMethod("getPeerCertificates",
                   (Class [])null));
        } catch (Exception ex) {
            supported = false;
            try {
                fact = CertificateFactory.getInstance("X.509");
            } catch (Exception sub) {
                fact = null;
            }
        }
        finally {
            supportsNewStyleCertificates = supported;
            x509Factory  = fact;
        }
    }
 
    /**
     * flag for enabling debug output if applicable
     */
    private static boolean debug = false;
   
    /**
     * The internal no laceholder object, which has a different than the
     * expected type
     */
    private static final Object NO_ENTRY = "null";
   
    /**
     * The servlet api spec request attribute name of the cipher suite
     */
    private static final String ALGORITHM =
                                          "javax.servlet.request.cipher_suite";
   
    /**
     * The servlet api spec request attribute name of the key size
     */
    private static final String KEYSIZE = "javax.servlet.request.key_size";
   
    /**
     * The servlet api spec request attribute name of the certificate chain
     */
    private static final String CERTCHAIN =
                                       "javax.servlet.request.X509Certificate";
   
    /**
     * The servlet api spec attribute value for client authentication
     */
    private static final String CLIENT_CERT_AUTH = "CLIENT_CERT";

   
    /**
     * flag indicating TLS support
     */
    private boolean ssl_enabled = false;
   
    /**
     * reference to the daemon in question
     */
    private httpd daemon = null;
   
    /**
     * uri of the daemon in question
     */
    private URL url = null;
   
    /**
     * Fills in the stack trace of a cause if possible with respect to the
     * api level.
     *
     * @param throwable  the thowable to be extended
     * @param cause  the cause to be filled in
     */ 
    public static final void fillInStackTrace(Throwable throwable,
                Throwable cause) {
        if (null != initCause) {
      try {
    Object[] param = { cause };
    initCause.invoke(throwable, param);
      } catch (Exception iex) {
                // ignore
            }
        }
    }
   
    /**
     * Supplies the ssl session attached to the specified request if any.
     *
     * @param request  the request in question
     * @return  the attached ssl session or null if not applicable
     */
    private static final SSLSession getSession(Request request) {
       Client cl = request.getClient();
  if (cl instanceof SSLSocketClient) {
      return ((SSLSocketClient)cl).getSession();
        }
        return null;
    }
   
    /**
     * An ugly way to compute the key size (to be improved)
     * @param algorithm  the algorithm name
     * @return the key size as an integer object
     */
    private static final Integer getKeySize(String algorithm) {
        if (null != algorithm) {
      StringTokenizer parser = new StringTokenizer(algorithm, "_");
      while (parser.hasMoreTokens()) {
    try {
        return Integer.valueOf(parser.nextToken());
    }
    catch (NumberFormatException ex) {
        // ignore and continue lookup
    }
      }
        }
        return null;
    }
   
    /**
     * Supplies the calculated or cached key size.
     * @param algorithm  the algorithm name
     * @param session  the ssl underlying session
     * @return the key size as an integer object
     */
    private static final Integer getKeySize(String algorithm,
              SSLSession session) {
       // FIXME: find a better way to compute the key size
       //        at least this ugly computation gets cached
     //        at the moment
  Object keysize = session.getValue(KEYSIZE + "." + algorithm);
  if (keysize instanceof Integer) {
      return (Integer)keysize;
  } else {
      if (null == keysize) {
    Integer keysize2 = getKeySize(algorithm);
    if (null != keysize2) {
        session.putValue(KEYSIZE+"."+algorithm, keysize2);
                    return keysize2;
    } else {
        session.putValue(KEYSIZE+"."+algorithm, NO_ENTRY);
        return null;
    }
      } else {
    return null; // keysize could not be computed,
                 //i.e. equals NO_ENTRY
      }
  }
    }
   
    /**
     * Supplies the peer certificates if available.
     *
     * @param session  the underlying ssl session
     * @return  the certificate chain or null
     * @throws SSLPeerUnverifiedException  iff certificates cannot be ontained
     */
    private static final Certificate[] getPeerCertificates(SSLSession session)
        throws SSLPeerUnverifiedException {
        try {
      // using introspection due to possible compatibility issues
      if (supportsNewStyleCertificates) {
    return session.getPeerCertificates();
      } else {
    // using deprecated method as a fallback with
    // explicit certificate conversion
    if (null != x509Factory) {
        javax.security.cert.X509Certificate[] oldStyleCerts;
        oldStyleCerts = session.getPeerCertificateChain();
        if (null != oldStyleCerts) {
      int count = oldStyleCerts.length;
      X509Certificate[] newStyleCerts;
      newStyleCerts =  new X509Certificate[count];
      for (int i = 0; i < count; i++) {
          newStyleCerts[i] =
           (X509Certificate)x509Factory.generateCertificate(
         new ByteArrayInputStream(
             oldStyleCerts[i].getEncoded()));
      }
      return newStyleCerts;
        } else {
      throw new SSLPeerUnverifiedException("No peer "+
                 "certificates available");
        }
    } else {
        throw new SSLPeerUnverifiedException("No suitable"+
                   " certificate compatibility applicable");
    }
      }
  } catch (SSLPeerUnverifiedException ex) {
      throw ex;
        } catch (Exception ex) {
      SSLPeerUnverifiedException sub;
      sub = new SSLPeerUnverifiedException(ex.toString());
      fillInStackTrace(sub, ex);
      throw sub;
        }
    }
   
    /**
     * constructor for a TLS support adapter
     * @param server reference to the daemon in question
     */
    public SSLAdapter(httpd server) {
        if (null != server) {
      ssl_enabled = false;
      daemon = server;
      url = null;
        } else {
      throw new NullPointerException("No daemon intance supplied for "+
             " creating SSL adapter");
  }
    }
   
    /**
     * method for initializing the properties of a daemon
     * @exception ServerHandlerInitException thrown if initialization fails
     */
    public void initializeProperties()
        throws ServerHandlerInitException
    {
        ObservableProperties props = daemon.getProperties();
        // default to well-known factory if applicable       
        if (props.getBoolean(SSLProperties.SSL_ENABLED_P, true)) {
            String factory_class = props.getString(httpd.CLIENT_FACTORY_P,
               null);
            if (null != factory_class) {
                try {
        Class factory = Class.forName(factory_class);
        ssl_enabled =
          (SSLSocketClientFactory.class.isAssignableFrom(factory));
                } catch (Exception ex) {
                    String error = "Initialization failed";
                    daemon.fatal(ex, error);
                    if (debug) {
                        System.out.println(error);
                        ex.printStackTrace();
                    }
                    ServerHandlerInitException sub;
                    sub = new ServerHandlerInitException(ex.getMessage());
                    fillInStackTrace(sub, ex);
                    throw sub;
                }
            } else {
    throw new ServerHandlerInitException("No socket client"
                 +" factory specified");
      }
        } else {
      ssl_enabled = false;
  }
        url = null;
    }

    /**
     * method for preparing a reply interface for a request
     * @param req the current request to be handled
     * @exception ProtocolException thrown if the request url is malformed
     */
    public void perform(RequestInterface req)
  throws ProtocolException  {
  Request request = (Request)req;
  if (ssl_enabled) {
      // set request protocol to https
      URL url = request.getURL();
      try {
    request.setURL(new URL("https", url.getHost(),
               url.getPort(), url.getFile()));
   
    // tk, 1 February 2004, added SSL client attributes
    // according to Servlet v2.4 spec
    SSLSession session = getSession(request);
    if (null != session) {
        String algorithm = session.getCipherSuite();
        request.setState(ALGORITHM, algorithm);
       
        Integer keysize = getKeySize(algorithm, session);
        if (null != keysize) {
      request.setState(KEYSIZE, keysize);
        }
       
        try {
                        Certificate[] chain = getPeerCertificates(session);
                        if (chain instanceof X509Certificate[]) {
                            X509Certificate[] x509chain;
          x509chain = (X509Certificate[])chain;
                            request.setState(CERTCHAIN, x509chain);
                            request.setState(AuthFilter.STATE_AUTHTYPE,
               CLIENT_CERT_AUTH);
                            if (x509chain.length > 0) {
        request.setState(AuthFilter.STATE_AUTHUSER,
                x509chain[0].getSubjectDN().getName());
                            }
                        }
        } catch (SSLPeerUnverifiedException ex) {
      if (debug) {
          ex.printStackTrace();
      }
      // no certificates available, ignore
        }
    }
      } catch (MalformedURLException ex) {
    String error = "Bad url during switching to https";
    daemon.fatal(ex, error);
    if (debug) {
        System.out.println(error);
        ex.printStackTrace();
    }
    ProtocolException sub = new ProtocolException(ex.getMessage());
    fillInStackTrace(sub, ex);
    throw sub;
      }
  }
    }
   
    /**
     * method for supplying a daemon uri
     * @return uri of the daemon in question
     */
    public URL getURL() {
        if (url == null) {
      if (ssl_enabled) {
    try {
        if (daemon.getPort() != 443) {
      url = new URL("https", daemon.getHost(),
              daemon.getPort(), "/");
        } else {
      url = new URL("https", daemon.getHost(), "/");
        }
    } catch (MalformedURLException ex) {
        if (debug) {
      ex.printStackTrace();
        }
        throw new RuntimeException("Unable to construct "+
                 "server uri. (" +
                 ex.getMessage() + ")");
    }
      } else {
    try {
        if (daemon.getPort() != 80 ) {
      url = new URL("http", daemon.getHost(),
              daemon.getPort(), "/");
        } else {
      url = new URL("http", daemon.getHost(), "/");
        }
    } catch (MalformedURLException ex) {
        throw new RuntimeException("Unable to construct"+
                 " server uri. (" +
                 ex.getMessage() + ")");
    }
      }
  }   
        return url;
    }
   
    /**
     * method for indicating TLS support
     * @return flag for indicating TLS support enabled
     */
    public boolean sslEnabled() {
  return ssl_enabled;
    }
}
TOP

Related Classes of org.w3c.jigsaw.https.SSLAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.