Package org.apache.cxf.transport.https

Source Code of org.apache.cxf.transport.https.HttpsURLConnectionFactory

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.transport.https;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.logging.Handler;
import java.util.logging.Logger;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.ReflectionInvokationHandler;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transport.http.HttpURLConnectionFactory;
import org.apache.cxf.transport.http.HttpURLConnectionInfo;

/**
* This HttpsURLConnectionFactory implements the HttpURLConnectionFactory
* for using the given SSL Policy to configure TLS connections for "https:"
* URLs.
*
*/
public final class HttpsURLConnectionFactory
    implements HttpURLConnectionFactory {
   
    /**
     * This constant holds the URL Protocol Identifier for HTTPS
     */
    public static final String HTTPS_URL_PROTOCOL_ID = "https";

    private static final long serialVersionUID = 1L;
    private static final Logger LOG =
        LogUtils.getL7dLogger(HttpsURLConnectionFactory.class);

    private static boolean weblogicWarned;
   
    /**
     * This field holds the conduit to which this connection factory
     * is a slave.
     */
    HTTPConduit conduit;
   
    /**
     * This field contains the TLS configuration for the URLs created by
     * this factory.
     */
    TLSClientParameters tlsClientParameters;
   
   
    /**
     * Cache the last SSLContext to avoid recreation
     */
    SSLSocketFactory socketFactory;
   
    /**
     * This constructor initialized the factory with the configured TLS
     * Client Parameters for the HTTPConduit for which this factory is used.
     *
     * @param params The TLS Client Parameters. This parameter is guaranteed
     *               to be non-null.
     */
    public HttpsURLConnectionFactory(TLSClientParameters params) {
        tlsClientParameters        = params;
        assert tlsClientParameters != null;
    }
   
    /**
     * Create a HttpURLConnection, proxified if necessary.
     *
     *
     * @param proxy This parameter is non-null if connection should be proxied.
     * @param url   The target URL. This parameter must be an https url.
     *
     * @return The HttpsURLConnection for the given URL.
     * @throws IOException This exception is thrown if
     *         the "url" is not "https" or other IOException
     *         is thrown.
     *                    
     */
    public HttpURLConnection createConnection(Proxy proxy, URL url)
        throws IOException {

        if (!url.getProtocol().equals(HTTPS_URL_PROTOCOL_ID)) {
            throw new IOException("Illegal Protocol "
                    + url.getProtocol()
                    + " for HTTPS URLConnection Factory.");
        }
       
        HttpURLConnection connection =
            (HttpURLConnection) (proxy != null
                                   ? url.openConnection(proxy)
                                   : url.openConnection());
                                  
        if (tlsClientParameters != null) {
            Exception ex = null;
            try {
                decorateWithTLS(connection);
            } catch (Exception e) {
                ex = e;
            } finally {
                if (ex != null) {
                    if (ex instanceof IOException) {
                        throw (IOException) ex;
                    }
                    // use exception.initCause(ex) to be java 5 compatible
                    IOException ioException = new IOException("Error while initializing secure socket");
                    ioException.initCause(ex);
                    throw ioException;
                }
            }
        }

        return connection;
    }
   
    /**
     * This method assigns the various TLS parameters on the HttpsURLConnection
     * from the TLS Client Parameters. Connection parameter is of supertype HttpURLConnection,
     * which allows internal cast to potentially divergent subtype (https) implementations.
     */
    protected synchronized void decorateWithTLS(HttpURLConnection connection)
        throws GeneralSecurityException {

        // always reload socketFactory from HttpsURLConnection.defaultSSLSocketFactory and
        // tlsClientParameters.sslSocketFactory to allow runtime configuration change
        if (tlsClientParameters.isUseHttpsURLConnectionDefaultSslSocketFactory()) {
            socketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
           
        } else if (tlsClientParameters.getSSLSocketFactory() != null) {
            // see if an SSLSocketFactory was set. This allows easy interop
            // with not-yet-commons-ssl.jar, or even just people who like doing their
            // own JSSE.
            socketFactory = tlsClientParameters.getSSLSocketFactory();
           
        } else if (socketFactory == null) {
            // ssl socket factory not yet instantiated, create a new one with tlsClientParameters's Trust
            // Managers, Key Managers, etc

            String provider = tlsClientParameters.getJsseProvider();

            String protocol = tlsClientParameters.getSecureSocketProtocol() != null ? tlsClientParameters
                .getSecureSocketProtocol() : "TLS";

            SSLContext ctx = provider == null ? SSLContext.getInstance(protocol) : SSLContext
                .getInstance(protocol, provider);

            ctx.init(tlsClientParameters.getKeyManagers(), tlsClientParameters.getTrustManagers(),
                     tlsClientParameters.getSecureRandom());

            // The "false" argument means opposite of exclude.
            String[] cipherSuites = SSLUtils.getCiphersuites(tlsClientParameters.getCipherSuites(), SSLUtils
                .getSupportedCipherSuites(ctx), tlsClientParameters.getCipherSuitesFilter(), LOG, false);
            // The SSLSocketFactoryWrapper enables certain cipher suites
            // from the policy.
            socketFactory = new SSLSocketFactoryWrapper(ctx.getSocketFactory(), cipherSuites,
                                                        tlsClientParameters.getSecureSocketProtocol());
        } else {
           // ssl socket factory already initialized, reuse it to benefit of keep alive
        }
       
       
        HostnameVerifier verifier;
        if (tlsClientParameters.isUseHttpsURLConnectionDefaultHostnameVerifier()) {
            verifier = HttpsURLConnection.getDefaultHostnameVerifier();
        } else if (tlsClientParameters.isDisableCNCheck()) {
            verifier = CertificateHostnameVerifier.ALLOW_ALL;
        } else {
            verifier = CertificateHostnameVerifier.DEFAULT;
        }
       
        if (connection instanceof HttpsURLConnection) {
            // handle the expected case (javax.net.ssl)
            HttpsURLConnection conn = (HttpsURLConnection) connection;
            conn.setHostnameVerifier(verifier);
            conn.setSSLSocketFactory(socketFactory);
        } else {
            // handle the deprecated sun case and other possible hidden API's
            // that are similar to the Sun cases
            try {
                Method method = connection.getClass().getMethod("getHostnameVerifier");
               
                InvocationHandler handler = new ReflectionInvokationHandler(verifier) {
                    public Object invoke(Object proxy,
                                         Method method,
                                         Object[] args) throws Throwable {
                        try {
                            return super.invoke(proxy, method, args);
                        } catch (Exception ex) {
                            return true;
                        }
                    }
                };
                Object proxy = java.lang.reflect.Proxy.newProxyInstance(this.getClass().getClassLoader(),
                                                                        new Class[] {method.getReturnType()},
                                                                        handler);

                method = connection.getClass().getMethod("setHostnameVerifier", method.getReturnType());
                method.invoke(connection, proxy);
            } catch (Exception ex) {
                //Ignore this one
            }
            try {
                Method getSSLSocketFactory =  connection.getClass().getMethod("getSSLSocketFactory");
                Method setSSLSocketFactory = connection.getClass()
                    .getMethod("setSSLSocketFactory", getSSLSocketFactory.getReturnType());
                if (getSSLSocketFactory.getReturnType().isInstance(socketFactory)) {
                    setSSLSocketFactory.invoke(connection, socketFactory);
                } else {
                    //need to see if we can create one - mostly the weblogic case.   The
                    //weblogic SSLSocketFactory has a protected constructor that can take
                    //a JSSE SSLSocketFactory so we'll try and use that
                    Constructor c = getSSLSocketFactory.getReturnType()
                        .getDeclaredConstructor(SSLSocketFactory.class);
                    c.setAccessible(true);
                    setSSLSocketFactory.invoke(connection, c.newInstance(socketFactory));
                }
            } catch (Exception ex) {
                if (connection.getClass().getName().contains("weblogic")) {
                    if (!weblogicWarned) {
                        weblogicWarned = true;
                        LOG.warning("Could not configure SSLSocketFactory on Weblogic.  "
                                    + " Use the Weblogic control panel to configure the SSL settings.");
                    }
                    return;
                }
                //if we cannot set the SSLSocketFactor, we're in serious trouble.
                throw new IllegalArgumentException("Error decorating connection class "
                        + connection.getClass().getName(), ex);
            }
        }
    }

    /*
     *  For development and testing only
     */
    protected void addLogHandler(Handler handler) {
        LOG.addHandler(handler);
    }

    /**
     * This operation returns an HttpsURLConnectionInfo for the
     * given HttpsURLConnection.
     *
     * @param connection The HttpsURLConnection
     * @return The HttpsURLConnectionInfo object for the given
     *         HttpsURLConnection.
     * @throws IOException Normal IO Exceptions.
     * @throws ClassCastException If "connection" is not an HttpsURLConnection
     *         (or a supported subtype of HttpURLConnection)
     */
    public HttpURLConnectionInfo getConnectionInfo(
            HttpURLConnection connection
    ) throws IOException
        return new HttpsURLConnectionInfo(connection);
    }
   
    public String getProtocol() {
        return "https";
    }

}


TOP

Related Classes of org.apache.cxf.transport.https.HttpsURLConnectionFactory

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.