Package com.sun.enterprise.web.connector.grizzly.ssl

Source Code of com.sun.enterprise.web.connector.grizzly.ssl.SSLSelectorThread

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package com.sun.enterprise.web.connector.grizzly.ssl;

import com.sun.enterprise.web.connector.grizzly.Pipeline;
import com.sun.enterprise.web.connector.grizzly.ReadTask;
import com.sun.enterprise.web.connector.grizzly.DefaultReadTask;
import com.sun.enterprise.web.connector.grizzly.ProcessorTask;
import com.sun.enterprise.web.connector.grizzly.SecureSelector;
import com.sun.enterprise.web.connector.grizzly.SelectorThread;
import com.sun.enterprise.web.connector.grizzly.StreamAlgorithm;
import com.sun.enterprise.web.connector.grizzly.algorithms.NoParsingAlgorithm;
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import org.apache.tomcat.util.net.SSLImplementation;
import org.apache.tomcat.util.net.ServerSocketFactory;

/**
* SSL over NIO <code>Selector</code> implementation. Mainly, this class
* replace the clear text implementation by defining the SSL tasks counterpart:
* SSLReadTask, SSLProcessorTask and SSLByteBufferInputStream.
*
* The SSLPipeline is the default and must not be replace unless all its
* attribute properly implemented.
*
* @author Jean-Francois Arcand
*/
public class SSLSelectorThread extends SelectorThread
        implements SecureSelector<SSLImplementation>{
   
   
    /**
     * The <code>SSLImplementation</code>
     */
    private SSLImplementation sslImplementation;
   
   
    /**
     * The <code>SSLContext</code> associated with the SSL implementation
     * we are running on.
     */
    protected SSLContext sslContext;
   
   
    /**
     * The list of cipher suite
     */
    private String[] enabledCipherSuites = null;
   
   
    /**
     * the list of protocols
     */
    private String[] enabledProtocols = null;
   
   
    /**
     * Client mode when handshaking.
     */
    private boolean clientMode = false;
   
   
    /**
     * Require client Authentication.
     */
    private boolean needClientAuth = false;
   
   
    /**
     * True when requesting authentication.
     */
    private boolean wantClientAuth = false;   
   
   
    /**
     * Has the enabled protocol configured.
     */
    private boolean isProtocolConfigured = false;
   
   
    /**
     * Has the enabled Cipher configured.
     */
    private boolean isCipherConfigured = false;
   
    // ---------------------------------------------------------------------/.
   
   
    public SSLSelectorThread(){
        super();
        setPipelineClassName(com.sun.enterprise.web.connector.grizzly.ssl.
                SSLPipeline.class.getName());
    }

   
    /**
     * Initialize <code>SSLSelectorReadThread</code> used to process
     * OP_READ operations.
     */
    @Override
    protected void initMultiSelectors() throws IOException,
                                                 InstantiationException {
        for (int i = 0; i < readThreads.length; i++) {
            readThreads[i] = new SSLSelectorReadThread(){
                public ReadTask getReadTask(SelectionKey key)
                    throws IOException{

                    ReadTask readTask = SSLSelectorThread.this.getReadTask(key);
                    readTask.setSelectorThread(this);
                    return readTask;
                }
            };
            ((SSLSelectorReadThread)readThreads[i]).countName = i;
            configureReadThread((SSLSelectorReadThread)readThreads[i]);
        }
    }
   
    /**
     * Enable all registered interestOps. Due a a NIO bug, all interestOps
     * invocation needs to occurs on the same thread as the selector thread.
     */
    @Override
    public void enableSelectionKeys(){
        SelectionKey selectionKey;
        int size = getKeysToEnable().size();
        long currentTime = System.currentTimeMillis();
        for (int i=0; i < size; i++) {
            selectionKey = (SelectionKey)getKeysToEnable().poll();

            selectionKey.interestOps(
                    selectionKey.interestOps() | SelectionKey.OP_READ);

            if ( selectionKey.attachment() != null){
                ((SSLEngine)selectionKey
                        .attachment()).getSession().putValue
                            (String.valueOf(selectionKey.hashCode()), System.currentTimeMillis());
            }
            keepAlivePipeline.trap(selectionKey);  
        }
    }
   
   
    /**
     * Handle OP_READ
     */
    @Override
    protected ReadTask handleRead(SelectionKey key) throws IOException{                  
        // disable OP_READ on key before doing anything else
        key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
       
        if (enableNioLogging){
            logger.log(Level.INFO,"Handling OP_READ on SocketChannel " +
                    key.channel());
        }     
       
        return getReadTask(key);
    }   
   
   
    /**
     * Cancel keep-alive connections.
     */
    @Override
    protected void expireIdleKeys() {
        if (keepAliveTimeoutInSeconds <= 0 || !selector.isOpen()) return;
        long current = System.currentTimeMillis();

        if (current < getNextKeysExpiration()) {
            return;
        }
        setNextKeysExpiration(current + getKaTimeout());
       
        Set<SelectionKey> readyKeys = selector.keys();
        if (readyKeys.isEmpty()){
            return;
        }
        Iterator<SelectionKey> iterator = readyKeys.iterator();
        SelectionKey key;
        while (iterator.hasNext()) {
            key = (SelectionKey)iterator.next();
            if ( !key.isValid() ) {
                keepAlivePipeline.untrap(key);
                continue;
            }
           
            // Keep-alive expired
            final Object attachment = key.attachment();
            if (attachment != null) {               
                SSLSession sslSession = null;
                long expire = -1L;
                if (attachment instanceof SSLEngine){
                    sslSession = ((SSLEngine)attachment).getSession();
                    String hashString = String.valueOf(key.hashCode());
                    if (sslSession != null
                            && sslSession.getValue(hashString) != null){
                        expire = (Long)sslSession.getValue(hashString);
                    }
                } else if (attachment instanceof Long){
                    expire = (Long) attachment;
                }
               
                if (expire != -1L){
                    if (current - expire >= getKaTimeout()) {                  
                        cancelKey(key);
                    } else if (expire + getKaTimeout() < getNextKeysExpiration()){
                        setNextKeysExpiration(expire + getKaTimeout());
                    }
                }
            }
        }                   
    }
   
   
    /**
     * Register a <code>SelectionKey</code> to this <code>Selector</code>
     * running of this thread.
     */
    @Override
    public void registerKey(SelectionKey key){
        if (key == null) return;
       
        if (keepAlivePipeline.dropConnection()) {
            cancelKey(key);
            return;
        }

        if (enableNioLogging){
            logger.log(Level.INFO,
                    "Registering SocketChannel for keep alive "
                    key.channel());
        }        
        getKeysToEnable().add(key);
        selector.wakeup();
    }
   
    /**
     * Create a new <code>Pipeline</code> instance using the
     * <code>pipelineClassName</code> value.
     */
    @Override
    protected Pipeline newPipeline(int maxThreads,
                                   int minThreads,
                                   String name,
                                   int port,
                                   int priority){
       
        Class className = null;                              
        Pipeline pipeline = null;                              
        try{                             
            className = Class.forName(getPipelineClassName());
            pipeline = (Pipeline)className.newInstance();
        } catch (ClassNotFoundException ex){
            getLogger().log(Level.WARNING,
                       "Unable to load Pipeline: " + getPipelineClassName());
            pipeline = new SSLPipeline();
        } catch (InstantiationException ex){
            getLogger().log(Level.WARNING,
                       "Unable to instantiate Pipeline: "
                       + getPipelineClassName());
            pipeline = new SSLPipeline();
        } catch (IllegalAccessException ex){
            getLogger().log(Level.WARNING,
                       "Unable to instantiate Pipeline: "
                       + getPipelineClassName());
            pipeline = new SSLPipeline();
        }
       
        if (getLogger().isLoggable(Level.FINE)){
            getLogger().log(Level.FINE,
                       "http-listener " + port + " uses pipeline: "
                       + pipeline.getClass().getName());
        }
       
        pipeline.setMaxThreads(maxThreads);
        pipeline.setMinThreads(minThreads);   
        pipeline.setName(name);
        pipeline.setPort(port);
        pipeline.setPriority(priority);
        pipeline.setQueueSizeInBytes(getMaxQueueSizeInBytes());
        pipeline.setThreadsIncrement(getThreadsIncrement());
        pipeline.setThreadsTimeout(getThreadsTimeout());
       
        return pipeline;
   
    }

   
    /**
     * Return a <code>SSLReadTask</code> from the pool. If the pool is empty,
     * create a new instance. Make sure the SSLEngine is reused when the
     * SelectionKey is part of a keep-alive transaction.
     */
    @Override
    public ReadTask getReadTask(SelectionKey key) throws IOException{
        ReadTask task = super.getReadTask(key);
       
        SSLEngine sslEngine = null;
        Object attachment = key.attachment();
        if (attachment != null && attachment instanceof SSLEngine){
            sslEngine = (SSLEngine)attachment;
        } else {
            key.attach(null);
        }
       
        if (sslEngine != null) {
            ((SSLReadTask)task).setHandshake(false);
        } else {
            sslEngine = sslContext.createSSLEngine();
            if (enabledCipherSuites != null){               
                if (!isCipherConfigured) {
                    enabledCipherSuites = configureEnabledCiphers(sslEngine,
                            enabledCipherSuites);
                    isCipherConfigured = true;
                }               
                sslEngine.setEnabledCipherSuites(enabledCipherSuites);
            }

            if (enabledProtocols != null){               
                if (!isProtocolConfigured) {
                    enabledProtocols = configureEnabledProtocols(sslEngine,
                                                                 enabledProtocols);
                    isProtocolConfigured = true;
                }               
                sslEngine.setEnabledProtocols(enabledProtocols);
            }      
            sslEngine.setUseClientMode(isClientMode());
        }
        sslEngine.getSession().removeValue(String.valueOf(key.hashCode()));

        // Carefully set need/want flags, because according to the SSLEngine javadoc, they reset each other.
        if (isNeedClientAuth()) {
            sslEngine.setNeedClientAuth(true);
        } else if (isWantClientAuth()) {
            sslEngine.setWantClientAuth(true);
        } else {
            sslEngine.setNeedClientAuth(false);
        }

        ((SSLReadTask)task).setSSLEngine(sslEngine);          
        return task;
    }          
   
   
    /**
     * Return a new <code>SSLReadTask</code> instance
     */
    @Override
    protected DefaultReadTask newReadTask(){
        StreamAlgorithm streamAlgorithm = new NoParsingAlgorithm();   
        streamAlgorithm.setPort(getPort());
              
        SSLReadTask task;
        if (getMaxReadWorkerThreads() > 0 || asyncExecution){
            task =  new SSLAsyncReadTask()
        } else {
            task = new SSLReadTask();
        }
                    
        task.initialize(streamAlgorithm, isUseDirectByteBuffer(), isUseByteBufferView());
        task.setPipeline(getReadPipeline())
        task.setSelectorThread(this);
        task.setRecycle(isRecycleTasks());
        task.setSSLImplementation(sslImplementation);
       
        return task;
    }
   
   
    /**
     * Create <code>SSLProcessorTask</code> objects and configure it to be ready
     * to proceed request.
     */
    @Override
    protected ProcessorTask newProcessorTask(boolean initialize){                                                     
        SSLProcessorTask task = null;
        if (!asyncExecution) {
            task = new SSLProcessorTask(initialize, isBufferResponse());
        } else {
            task = new SSLAsyncProcessorTask(initialize, isBufferResponse());
        }     
        return configureProcessorTask(task);       
    }
   
   
    /**
     * Set the SSLContext required to support SSL over NIO.
     */
    public void setSSLContext(SSLContext sslContext){
        this.sslContext = sslContext;
    }
   
    /**
     * Return the SSLContext required to support SSL over NIO.
     */   
    public SSLContext getSSLContext(){
        return sslContext;
    }
   
   
    /**
     * Set the Coyote SSLImplementation.
     */
    public void setSSLImplementation(SSLImplementation sslImplementation){
        this.sslImplementation = sslImplementation;
    }  

   
    /**
     * Return the current <code>SSLImplementation</code> this Thread
     */
    public SSLImplementation getSSLImplementation() {
        return sslImplementation;
    }
   
    /**
     * Returns the list of cipher suites to be enabled when {@link SSLEngine}
     * is initialized.
     *
     * @return <tt>null</tt> means 'use {@link SSLEngine}'s default.'
     */
    public String[] getEnabledCipherSuites() {
        return enabledCipherSuites;
    }

   
    /**
     * Sets the list of cipher suites to be enabled when {@link SSLEngine}
     * is initialized.
     *
     * @param cipherSuites <tt>null</tt> means 'use {@link SSLEngine}'s default.'
     */
    public void setEnabledCipherSuites(String[] enabledCipherSuites) {
        this.enabledCipherSuites = enabledCipherSuites;
    }

  
    /**
     * Returns the list of protocols to be enabled when {@link SSLEngine}
     * is initialized.
     *
     * @return <tt>null</tt> means 'use {@link SSLEngine}'s default.'
     */ 
    public String[] getEnabledProtocols() {
        return enabledProtocols;
    }

   
    /**
     * Sets the list of protocols to be enabled when {@link SSLEngine}
     * is initialized.
     *
     * @param protocols <tt>null</tt> means 'use {@link SSLEngine}'s default.'
     */   
    public void setEnabledProtocols(String[] enabledProtocols) {
        this.enabledProtocols = enabledProtocols;
    }

   
    /**
     * Returns <tt>true</tt> if the SSlEngine is set to use client mode
     * when handshaking.
     */
    public boolean isClientMode() {
        return clientMode;
    }


    /**
     * Configures the engine to use client (or server) mode when handshaking.
     */   
    public void setClientMode(boolean clientMode) {
        this.clientMode = clientMode;
    }

   
    /**
     * Returns <tt>true</tt> if the SSLEngine will <em>require</em>
     * client authentication.
     */  
    public boolean isNeedClientAuth() {
        return needClientAuth;
    }

   
    /**
     * Configures the engine to <em>require</em> client authentication.
     */   
    public void setNeedClientAuth(boolean needClientAuth) {
        this.needClientAuth = needClientAuth;
    }

   
    /**
     * Returns <tt>true</tt> if the engine will <em>request</em> client
     * authentication.
     */  
    public boolean isWantClientAuth() {
        return wantClientAuth;
    }

   
    /**
     * Configures the engine to <em>request</em> client authentication.
     */   
    public void setWantClientAuth(boolean wantClientAuth) {
        this.wantClientAuth = wantClientAuth;
    }
   
   
    /**
     * Return the list of allowed protocol.
     * @return String[] an array of supported protocols.
     */
    private final static String[] configureEnabledProtocols(
            SSLEngine sslEngine, String[] requestedProtocols){
       
        String[] supportedProtocols = sslEngine.getSupportedProtocols();
        String[] protocols = null;
        ArrayList<String> list = null;
        for(String supportedProtocol: supportedProtocols){       
            /*
             * Check to see if the requested protocol is among the
             * supported protocols, i.e., may be enabled
             */
            for(String protocol: requestedProtocols) {
                protocol = protocol.trim();
                if (supportedProtocol.equals(protocol)) {
                    if (list == null) {
                        list = new ArrayList<String>();
                    }
                    list.add(protocol);
                    break;
                }
            }
        }

        if (list != null) {
            protocols = list.toArray(new String[list.size()]);               
        }
        return protocols;
    }
   
   
    /*
     * Determines the SSL cipher suites to be enabled.
     *
     * @return Array of SSL cipher suites to be enabled, or null if none of the
     * requested ciphers are supported
     */
    private final static String[] configureEnabledCiphers(SSLEngine sslEngine,
            String[] requestedCiphers) {

        String[] supportedCiphers = sslEngine.getSupportedCipherSuites();
        String[] ciphers = null;
        ArrayList<String> list = null;
        for(String supportedCipher: supportedCiphers){       
            /*
             * Check to see if the requested protocol is among the
             * supported protocols, i.e., may be enabled
             */
            for(String cipher: requestedCiphers) {
                cipher = cipher.trim();
                if (supportedCipher.equals(cipher)) {
                    if (list == null) {
                        list = new ArrayList<String>();
                    }
                    list.add(cipher);
                    break;
                }
            }
        }

        if (list != null) {
            ciphers = list.toArray(new String[list.size()]);               
        }
        return ciphers;
    }
   
    /**
     * Initialize the fileCacheFactory associated with this instance
     */
    @Override
    protected void initFileCacheFactory(){
        fileCacheFactory = SSLFileCacheFactory.getFactory(port);
        fileCacheFactory.setIsEnabled(isFileCacheEnabled);
        fileCacheFactory.setLargeFileCacheEnabled(isLargeFileCacheEnabled);
        fileCacheFactory.setSecondsMaxAge(secondsMaxAge);
        fileCacheFactory.setMaxCacheEntries(maxCacheEntries);
        fileCacheFactory.setMinEntrySize(minEntrySize);
        fileCacheFactory.setMaxEntrySize(maxEntrySize);
        fileCacheFactory.setMaxLargeCacheSize(maxLargeFileCacheSize);
        fileCacheFactory.setMaxSmallCacheSize(maxSmallFileCacheSize);        
        fileCacheFactory.setIsMonitoringEnabled(isMonitoringEnabled);
    }
   
    // --------------------------------------------------- Not used/
   
    /**
     * Return the <code>ServerSocketFactory</code> used when a blocking IO
     * is enabled.
     */
    public ServerSocketFactory getServerSocketFactory(){
       return null;
    }

   
    /**
     * Set the <code>ServerSocketFactory</code> used when a blocking IO
     * is enabled.
     */  
    public void setServerSocketFactory(ServerSocketFactory factory){
       ;
    }
   
   
    /**
     * Enable gathering of monitoring datas.
     */
    @Override
    public void enableMonitoring(){
        isMonitoringEnabled = true;
        enablePipelineStats();     
        if (readThreads != null) {
            for (int i = 0; i < readThreads.length; i++) {
                ((SSLSelectorReadThread)readThreads[i]).isMonitoringEnabled = true;
            }
        }
        fileCacheFactory.setIsMonitoringEnabled(isMonitoringEnabled);
    }
   
   
    /**
     * Disable gathering of monitoring datas.
     */
    @Override
    public void disableMonitoring(){
        disablePipelineStats()
        if (readThreads != null) {
            for (int i = 0; i < readThreads.length; i++) {
                ((SSLSelectorReadThread)readThreads[i]).isMonitoringEnabled = false;
            }
        }
        fileCacheFactory.setIsMonitoringEnabled(isMonitoringEnabled);       
    }

   
}
TOP

Related Classes of com.sun.enterprise.web.connector.grizzly.ssl.SSLSelectorThread

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.