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

org.apache.catalina.core.AprLifecycleListener Maven / Gradle / Ivy

There is a newer version: 11.0.0-M20
Show newest version
/*
 * 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.catalina.core;


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jni.Library;
import org.apache.tomcat.jni.LibraryNotFoundError;
import org.apache.tomcat.jni.SSL;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.res.StringManager;



/**
 * Implementation of LifecycleListener that will init and
 * and destroy APR.
 *
 * @since 4.1
 */
public class AprLifecycleListener
    implements LifecycleListener {

    private static final Log log = LogFactory.getLog(AprLifecycleListener.class);
    /**
     * Info messages during init() are cached until Lifecycle.BEFORE_INIT_EVENT
     * so that, in normal (non-error) cases, init() related log messages appear
     * at the expected point in the lifecycle.
     */
    private static final List initInfoLogMessages = new ArrayList<>(3);

    /**
     * The string manager for this package.
     */
    protected static final StringManager sm =
        StringManager.getManager(Constants.Package);


    // ---------------------------------------------- Constants


    protected static final int TCN_REQUIRED_MAJOR = 1;
    protected static final int TCN_REQUIRED_MINOR = 2;
    protected static final int TCN_REQUIRED_PATCH = 14;
    protected static final int TCN_RECOMMENDED_MINOR = 2;
    protected static final int TCN_RECOMMENDED_PV = 23;


    // ---------------------------------------------- Properties
    protected static String SSLEngine = "on"; //default on
    protected static String FIPSMode = "off"; // default off, valid only when SSLEngine="on"
    protected static String SSLRandomSeed = "builtin";
    protected static boolean sslInitialized = false;
    protected static boolean fipsModeActive = false;

    /**
     * The "FIPS mode" level that we use as the argument to OpenSSL method
     * FIPS_mode_set() to enable FIPS mode and that we expect as
     * the return value of FIPS_mode() when FIPS mode is enabled.
     * 

* In the future the OpenSSL library might grow support for different * non-zero "FIPS" modes that specify different allowed subsets of ciphers * or whatever, but nowadays only "1" is the supported value. *

* @see OpenSSL method FIPS_mode_set() * @see OpenSSL method FIPS_mode() */ private static final int FIPS_ON = 1; private static final int FIPS_OFF = 0; protected static final Object lock = new Object(); public static boolean isAprAvailable() { //https://bz.apache.org/bugzilla/show_bug.cgi?id=48613 if (AprStatus.isInstanceCreated()) { synchronized (lock) { init(); } } return AprStatus.isAprAvailable(); } public AprLifecycleListener() { AprStatus.setInstanceCreated(true); } // ---------------------------------------------- LifecycleListener Methods /** * Primary entry point for startup and shutdown events. * * @param event The event that has occurred */ @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) { synchronized (lock) { init(); for (String msg : initInfoLogMessages) { log.info(msg); } initInfoLogMessages.clear(); if (AprStatus.isAprAvailable()) { try { initializeSSL(); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); log.error(sm.getString("aprListener.sslInit"), t); } } // Failure to initialize FIPS mode is fatal if (!(null == FIPSMode || "off".equalsIgnoreCase(FIPSMode)) && !isFIPSModeActive()) { String errorMessage = sm.getString("aprListener.initializeFIPSFailed"); Error e = new Error(errorMessage); // Log here, because thrown error might be not logged log.fatal(errorMessage, e); throw e; } } } else if (Lifecycle.AFTER_DESTROY_EVENT.equals(event.getType())) { synchronized (lock) { if (!AprStatus.isAprAvailable()) { return; } try { terminateAPR(); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); log.info(sm.getString("aprListener.aprDestroy")); } } } } private static void terminateAPR() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { String methodName = "terminate"; Method method = Class.forName("org.apache.tomcat.jni.Library") .getMethod(methodName, (Class [])null); method.invoke(null, (Object []) null); AprStatus.setAprAvailable(false); AprStatus.setAprInitialized(false); sslInitialized = false; // Well we cleaned the pool in terminate. fipsModeActive = false; } private static void init() { int major = 0; int minor = 0; int patch = 0; int apver = 0; int rqver = TCN_REQUIRED_MAJOR * 1000 + TCN_REQUIRED_MINOR * 100 + TCN_REQUIRED_PATCH; int rcver = TCN_REQUIRED_MAJOR * 1000 + TCN_RECOMMENDED_MINOR * 100 + TCN_RECOMMENDED_PV; if (AprStatus.isAprInitialized()) { return; } AprStatus.setAprInitialized(true); try { Library.initialize(null); major = Library.TCN_MAJOR_VERSION; minor = Library.TCN_MINOR_VERSION; patch = Library.TCN_PATCH_VERSION; apver = major * 1000 + minor * 100 + patch; } catch (LibraryNotFoundError lnfe) { // Library not on path if (log.isDebugEnabled()) { log.debug(sm.getString("aprListener.aprInitDebug", lnfe.getLibraryNames(), System.getProperty("java.library.path"), lnfe.getMessage()), lnfe); } initInfoLogMessages.add(sm.getString("aprListener.aprInit", System.getProperty("java.library.path"))); return; } catch (Throwable t) { // Library present but failed to load t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); log.warn(sm.getString("aprListener.aprInitError", t.getMessage()), t); return; } if (apver < rqver) { log.error(sm.getString("aprListener.tcnInvalid", major + "." + minor + "." + patch, TCN_REQUIRED_MAJOR + "." + TCN_REQUIRED_MINOR + "." + TCN_REQUIRED_PATCH)); try { // Terminate the APR in case the version // is below required. terminateAPR(); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); } return; } if (apver < rcver) { initInfoLogMessages.add(sm.getString("aprListener.tcnVersion", major + "." + minor + "." + patch, TCN_REQUIRED_MAJOR + "." + TCN_RECOMMENDED_MINOR + "." + TCN_RECOMMENDED_PV)); } initInfoLogMessages.add(sm.getString("aprListener.tcnValid", major + "." + minor + "." + patch, Library.APR_MAJOR_VERSION + "." + Library.APR_MINOR_VERSION + "." + Library.APR_PATCH_VERSION)); // Log APR flags initInfoLogMessages.add(sm.getString("aprListener.flags", Boolean.valueOf(Library.APR_HAVE_IPV6), Boolean.valueOf(Library.APR_HAS_SENDFILE), Boolean.valueOf(Library.APR_HAS_SO_ACCEPTFILTER), Boolean.valueOf(Library.APR_HAS_RANDOM), Boolean.valueOf(Library.APR_HAVE_UNIX))); AprStatus.setAprAvailable(true); } private static void initializeSSL() throws Exception { if ("off".equalsIgnoreCase(SSLEngine)) { return; } if (sslInitialized) { //only once per VM return; } sslInitialized = true; String methodName = "randSet"; Class paramTypes[] = new Class[1]; paramTypes[0] = String.class; Object paramValues[] = new Object[1]; paramValues[0] = SSLRandomSeed; Class clazz = Class.forName("org.apache.tomcat.jni.SSL"); Method method = clazz.getMethod(methodName, paramTypes); method.invoke(null, paramValues); methodName = "initialize"; paramValues[0] = "on".equalsIgnoreCase(SSLEngine)?null:SSLEngine; method = clazz.getMethod(methodName, paramTypes); method.invoke(null, paramValues); if (!(null == FIPSMode || "off".equalsIgnoreCase(FIPSMode))) { fipsModeActive = false; final boolean enterFipsMode; int fipsModeState = SSL.fipsModeGet(); if(log.isDebugEnabled()) { log.debug(sm.getString("aprListener.currentFIPSMode", Integer.valueOf(fipsModeState))); } if ("on".equalsIgnoreCase(FIPSMode)) { if (fipsModeState == FIPS_ON) { log.info(sm.getString("aprListener.skipFIPSInitialization")); fipsModeActive = true; enterFipsMode = false; } else { enterFipsMode = true; } } else if ("require".equalsIgnoreCase(FIPSMode)) { if (fipsModeState == FIPS_ON) { fipsModeActive = true; enterFipsMode = false; } else { throw new IllegalStateException( sm.getString("aprListener.requireNotInFIPSMode")); } } else if ("enter".equalsIgnoreCase(FIPSMode)) { if (fipsModeState == FIPS_OFF) { enterFipsMode = true; } else { throw new IllegalStateException(sm.getString( "aprListener.enterAlreadyInFIPSMode", Integer.valueOf(fipsModeState))); } } else { throw new IllegalArgumentException(sm.getString( "aprListener.wrongFIPSMode", FIPSMode)); } if (enterFipsMode) { log.info(sm.getString("aprListener.initializingFIPS")); fipsModeState = SSL.fipsModeSet(FIPS_ON); if (fipsModeState != FIPS_ON) { // This case should be handled by the native method, // but we'll make absolutely sure, here. String message = sm.getString("aprListener.initializeFIPSFailed"); log.error(message); throw new IllegalStateException(message); } fipsModeActive = true; log.info(sm.getString("aprListener.initializeFIPSSuccess")); } } log.info(sm.getString("aprListener.initializedOpenSSL", SSL.versionString())); } public String getSSLEngine() { return SSLEngine; } public void setSSLEngine(String SSLEngine) { if (!SSLEngine.equals(AprLifecycleListener.SSLEngine)) { // Ensure that the SSLEngine is consistent with that used for SSL init if (sslInitialized) { throw new IllegalStateException( sm.getString("aprListener.tooLateForSSLEngine")); } AprLifecycleListener.SSLEngine = SSLEngine; } } public String getSSLRandomSeed() { return SSLRandomSeed; } public void setSSLRandomSeed(String SSLRandomSeed) { if (!SSLRandomSeed.equals(AprLifecycleListener.SSLRandomSeed)) { // Ensure that the random seed is consistent with that used for SSL init if (sslInitialized) { throw new IllegalStateException( sm.getString("aprListener.tooLateForSSLRandomSeed")); } AprLifecycleListener.SSLRandomSeed = SSLRandomSeed; } } public String getFIPSMode() { return FIPSMode; } public void setFIPSMode(String FIPSMode) { if (!FIPSMode.equals(AprLifecycleListener.FIPSMode)) { // Ensure that the FIPS mode is consistent with that used for SSL init if (sslInitialized) { throw new IllegalStateException( sm.getString("aprListener.tooLateForFIPSMode")); } AprLifecycleListener.FIPSMode = FIPSMode; } } public boolean isFIPSModeActive() { return fipsModeActive; } public void setUseOpenSSL(boolean useOpenSSL) { if (useOpenSSL != AprStatus.getUseOpenSSL()) { AprStatus.setUseOpenSSL(useOpenSSL); } } public static boolean getUseOpenSSL() { return AprStatus.getUseOpenSSL(); } public static boolean isInstanceCreated() { return AprStatus.isInstanceCreated(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy