All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.security.ssl.impl.SecuritySupportImpl Maven / Gradle / Ivy

There is a newer version: 4.1.2.181
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2013 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.security.ssl.impl;

import com.sun.enterprise.security.ssl.manager.UnifiedX509KeyManager;
import com.sun.enterprise.security.ssl.manager.UnifiedX509TrustManager;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.security.KeyStore;
import java.security.Provider;

//V3:Commented import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.server.pluggable.SecuritySupport;
import java.io.IOException;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.Key;
import java.security.Permission;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.PropertyPermission;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import org.glassfish.api.admin.ProcessEnvironment;
import org.glassfish.api.admin.ProcessEnvironment.ProcessType;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.embedded.Server;
import org.glassfish.internal.api.Globals;
import org.glassfish.logging.annotation.LogMessageInfo;
import org.glassfish.logging.annotation.LogMessagesResourceBundle;
import org.glassfish.logging.annotation.LoggerInfo;

import javax.inject.Inject;
import org.jvnet.hk2.annotations.Service;

import javax.inject.Singleton;

/**
 * This implements SecuritySupport used in PluggableFeatureFactory.
 * @author Shing Wai Chan
 */
// TODO: when we have two SecuritySupport implementations,
// we create Habitat we'll select which SecuritySupport implementation to use.
@Service
@Singleton
public class SecuritySupportImpl extends SecuritySupport {
    private static final String DEFAULT_KEYSTORE_PASS = "changeit";
    private static final String DEFAULT_TRUSTSTORE_PASS = "changeit";
    
    @LogMessagesResourceBundle
    public static final String SHARED_LOGMESSAGE_RESOURCE = "com.sun.enterprise.security.ssl.LogMessages";
    
    @LoggerInfo(subsystem = "SECURITY - SSL", description = "Security - SSL", publish = true)
    public static final String SEC_SSL_LOGGER = "javax.enterprise.system.security.ssl";

    protected static final Logger _logger =
            Logger.getLogger(SEC_SSL_LOGGER, SHARED_LOGMESSAGE_RESOURCE);
    
    @LogMessageInfo(
			message = "The SSL certificate has expired: {0}",
			level = "SEVERE",
			cause = "Certificate expired.",
			action = "Check the expiration date of the certicate.")
	private static final String SSL_CERT_EXPIRED = "NCLS-SECURITY-05054";
    
    private static boolean initialized = false;
    protected static final List keyStores = new ArrayList();
    protected static final List trustStores = new ArrayList();
    protected static final List keyStorePasswords = new ArrayList();
    protected static final List tokenNames = new ArrayList();
    private MasterPasswordImpl masterPasswordHelper = null;
    private static boolean instantiated = false;
    private Date initDate = new Date();

    @Inject
    private ServiceLocator habitat;
    @Inject
    private ProcessEnvironment penv;

    public SecuritySupportImpl() {
        this(true);
    }

    protected SecuritySupportImpl(boolean init) {
        if (init) {
            initJKS();
        }
    }

    private void initJKS() {
        String keyStoreFileName = null;
        String trustStoreFileName = null;

        keyStoreFileName = System.getProperty(keyStoreProp);
        trustStoreFileName = System.getProperty(trustStoreProp);

        char[] keyStorePass = null;
        char[] trustStorePass = null;
        if (!isInstantiated()) {
            if (habitat == null) {
                habitat = Globals.getDefaultHabitat();
            }
            if (masterPasswordHelper == null && habitat != null) {
                masterPasswordHelper = habitat.getService(MasterPasswordImpl.class);
            }
            if (masterPasswordHelper != null) {
                keyStorePass = masterPasswordHelper.getMasterPassword();
                trustStorePass = keyStorePass;
            }
        }
        if (penv == null && habitat != null) {
            penv = habitat.getService(ProcessEnvironment.class);
        }
        /*
         * If we don't have a keystore password yet check the properties.
         * Always do so for the app client case whether the passwords have been
         * found from master password helper or not.
         */
        if (keyStorePass == null || isACC()) {
            final String keyStorePassOverride = System.getProperty(KEYSTORE_PASS_PROP, DEFAULT_KEYSTORE_PASS);
            if (keyStorePassOverride != null) {
                keyStorePass = keyStorePassOverride.toCharArray();
            }
            final String trustStorePassOverride = System.getProperty(TRUSTSTORE_PASS_PROP, DEFAULT_TRUSTSTORE_PASS);
            if (trustStorePassOverride != null){
                trustStorePass = trustStorePassOverride.toCharArray();
            }
        }

        if (!initialized) {
            loadStores(
                    null,
                    null,
                    keyStoreFileName,
                    keyStorePass,
                    System.getProperty(KEYSTORE_TYPE_PROP, KeyStore.getDefaultType()),
                    trustStoreFileName,
                    trustStorePass,
                    System.getProperty(TRUSTSTORE_TYPE_PROP, KeyStore.getDefaultType()));
            Arrays.fill(keyStorePass, ' ');
            Arrays.fill(trustStorePass, ' ');
            initialized = true;
        }
    }

    private boolean isEmbeddedServer() {
        List servers = Server.getServerNames();
        if (!servers.isEmpty()) {
            return true;
        }
        return false;
    }

    private static synchronized boolean isInstantiated() {
        if (!instantiated) {
            instantiated = true;
            return false;
        }
        return true;
    }

    /**
     * This method will load keystore and truststore and add into
     * corresponding list.
     * @param tokenName
     * @param provider
     * @param keyStorePass
     * @param keyStoreFile
     * @param keyStoreType
     * @param trustStorePass
     * @param trustStoreFile
     * @param trustStoreType
     */
    /*protected synchronized static void loadStores(String tokenName, 
    String storeType, Provider provider,
    String keyStoreFile, String keyStorePass,
    String trustStoreFile, String trustStorePass) {*/
    protected synchronized static void loadStores(
            String tokenName,
            Provider provider,
            String keyStoreFile,
            char[] keyStorePass,
            String keyStoreType,
            String trustStoreFile,
            char[] trustStorePass,
            String trustStoreType) {

        try {
            KeyStore keyStore = loadKS(keyStoreType, provider, keyStoreFile,
                    keyStorePass);
            KeyStore trustStore = loadKS(trustStoreType, provider, trustStoreFile,
                    trustStorePass);
            keyStores.add(keyStore);
            trustStores.add(trustStore);
            keyStorePasswords.add(Arrays.copyOf(keyStorePass, keyStorePass.length));
            tokenNames.add(tokenName);
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
    }

    /**
     * This method load keystore with given keystore file and
     * keystore password for a given keystore type and provider.
     * It always return a non-null keystore.
     * @param keyStoreType
     * @param provider
     * @param keyStoreFile
     * @param keyStorePass
     * @retun keystore loaded
     */
    private static KeyStore loadKS(String keyStoreType, Provider provider,
            String keyStoreFile, char[] keyStorePass)
            throws Exception {
        KeyStore ks = null;
        if (provider != null) {
            ks = KeyStore.getInstance(keyStoreType, provider);
        } else {
            ks = KeyStore.getInstance(keyStoreType);
        }
        char[] passphrase = keyStorePass;

        FileInputStream istream = null;
        BufferedInputStream bstream = null;
        try {
            if (keyStoreFile != null) {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, "Loading keystoreFile = {0}, keystorePass = {1}",
                            new Object[]{keyStoreFile, keyStorePass});
                }
                istream = new FileInputStream(keyStoreFile);
                bstream = new BufferedInputStream(istream);
            }

            ks.load(bstream, passphrase);
        } finally {
            if (bstream != null) {
                bstream.close();
            }
            if (istream != null) {
                istream.close();
            }
        }
        return ks;
    }

    // --- implements SecuritySupport ---
    /**
     * This method returns an array of keystores containing keys and
     * certificates.
     */
    public KeyStore[] getKeyStores() {
        return keyStores.toArray(new KeyStore[keyStores.size()]);
    }

    public KeyStore loadNullStore(String type, int index) throws KeyStoreException,
            IOException, NoSuchAlgorithmException, CertificateException {
        KeyStore ret = KeyStore.getInstance(type);
        ret.load(null, keyStorePasswords.get(index));
        return ret;
    }

    public KeyManager[] getKeyManagers(String algorithm) throws IOException,
            KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
        KeyStore[] kstores = getKeyStores();
        ArrayList keyManagers = new ArrayList();
        for (int i = 0; i < kstores.length; i++) {
            checkCertificateDates(kstores[i]);
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(
                    (algorithm != null) ? algorithm : KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(kstores[i], keyStorePasswords.get(i));
            KeyManager[] kmgrs = kmf.getKeyManagers();
            if (kmgrs != null) {
                keyManagers.addAll(Arrays.asList(kmgrs));
            }
        }

        KeyManager keyManager = new UnifiedX509KeyManager(
                keyManagers.toArray(new X509KeyManager[keyManagers.size()]),
                getTokenNames());
        return new KeyManager[]{keyManager};
    }

    public TrustManager[] getTrustManagers(String algorithm) throws IOException,
            KeyStoreException, NoSuchAlgorithmException {
        KeyStore[] tstores = getTrustStores();
        ArrayList trustManagers = new ArrayList();
        for (KeyStore tstore : tstores) {
            checkCertificateDates(tstore);
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(
                    (algorithm != null) ? algorithm : TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(tstore);
            TrustManager[] tmgrs = tmf.getTrustManagers();
            if (tmgrs != null) {
                trustManagers.addAll(Arrays.asList(tmgrs));
            }
        }
        TrustManager trustManager;
        if (trustManagers.size() == 1) {
            trustManager = trustManagers.get(0);
        } else {
            trustManager = new UnifiedX509TrustManager(trustManagers.toArray(new X509TrustManager[trustManagers.size()]));
        }
        return new TrustManager[]{trustManager};
    }
    /*
     * Check X509 certificates in a store for expiration.
     */

    private void checkCertificateDates(KeyStore store)
            throws KeyStoreException {

        Enumeration aliases = store.aliases();
        while (aliases.hasMoreElements()) {
            Certificate cert = store.getCertificate(aliases.nextElement());
            if (cert instanceof X509Certificate) {
                if (((X509Certificate) cert).getNotAfter().before(initDate)) {
                    _logger.log(Level.SEVERE, SSL_CERT_EXPIRED, cert);
                }
            }
        }
    }

    /**
     * This method returns an array of truststores containing certificates.
     */
    public KeyStore[] getTrustStores() {
        return trustStores.toArray(new KeyStore[trustStores.size()]);
    }

    public boolean verifyMasterPassword(final char[] masterPass) {
        return Arrays.equals(masterPass, keyStorePasswords.get(0));
    }

    /**
     * This method returns an array of token names in order corresponding to
     * array of keystores.
     */
    public String[] getTokenNames() {
        return tokenNames.toArray(new String[tokenNames.size()]);
    }

    /**
     * @param  token 
     * @return a keystore
     */
    public KeyStore getKeyStore(String token) {
        int idx = getTokenIndex(token);
        if (idx < 0) {
            return null;
        }
        return keyStores.get(idx);
    }

    /**
     * @param  token 
     * @return a truststore
     */
    public KeyStore getTrustStore(String token) {
        int idx = getTokenIndex(token);
        if (idx < 0) {
            return null;
        }
        return trustStores.get(idx);
    }

    /**
     * @return returned index 
     */
    private int getTokenIndex(String token) {
        int idx = -1;
        if (token != null) {
            idx = tokenNames.indexOf(token);
            if (idx < 0 && _logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST, "token {0} is not found", token);
            }
        }
        return idx;
    }

    public void synchronizeKeyFile(Object configContext, String fileRealmName) throws Exception {
        //throw new UnsupportedOperationException("Not supported yet in V3.");
    }

    public void checkPermission(String key) {
        try {
            // Checking a random permission to check if it is server.
            if(isEmbeddedServer() || habitat == null
                    || isACC() || isNotServerORACC()){
                return;
            }
            Permission perm = new RuntimePermission("SSLPassword");
            AccessController.checkPermission(perm);
        } catch (AccessControlException e) {
            String message = e.getMessage();
            Permission perm = new PropertyPermission(key, "read");
            if (message != null) {
                message = message.replace(e.getPermission().toString(), perm.toString());
            }
            throw new AccessControlException(message, perm);
        }
    }

    public boolean isACC() {
        return (penv == null ? false : penv.getProcessType().equals(ProcessType.ACC));
    }

    public boolean isNotServerORACC() {
        return penv.getProcessType().equals(ProcessType.Other);
    }

    public PrivateKey getPrivateKeyForAlias(String alias, int keystoreIndex) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
        checkPermission(KEYSTORE_PASS_PROP);
        Key key = keyStores.get(keystoreIndex).getKey(alias, keyStorePasswords.get(keystoreIndex));
        if (key instanceof PrivateKey) {
            return (PrivateKey) key;
        } else {
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy