SecureWebServer.java

/*
** Module   : SecureWebServer.java
** Abstract : Wev server with SSL support.
**
** Copyright (c) 2017-2022, Golden Code Development Corporation.
**
** -#- -I- --Date-- ----------------Description----------------------
** 001 SBI 20170925 Created initial version.
**     TJD 20220331 Replaced deprecated new SslContextFactory() with SslContextFactory.Server()
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
**
**   0. Attribution Requirement.
**
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
**
**   1. No License To Use Trademarks.
**
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
**
**   2. No Misrepresentation of Affiliation.
**
**     You may not represent yourself as Golden Code Development Corporation or FWD.
**
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
**
**   3. No Misrepresentation of Source or Origin.
**
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/
package com.goldencode.p2j.web;

import com.goldencode.p2j.security.*;
import org.eclipse.jetty.util.ssl.*;
import java.security.*;
import javax.net.ssl.*;

/**
 * Web server with SSL support.
 */
public class SecureWebServer
extends GenericWebServer
{
   /** Default HTTPS port */
   protected static int DEFAULT_PORT = 8443;
   
   /** Key store file name. */
   private String ksFileName = null;
   
   /** Key store password. */
   private String ksPasswd = null;
   
   /** Key entry password. */
   private String kePasswd = null;
   
   /** In-memory key store. */
   private KeyStore keyStore = null;
   
   /** Custom key manager. */
   private KeyManager[] km = null;
   
   /**
    * Construct an instance.
    *
    * @param   ksFileName
    *          Key store file name.
    * @param   ksPasswd
    *          Key store password or <code>null</code> if not needed.
    * @param   kePasswd
    *          Key entry password or <code>null</code> if not needed.
    */
   public SecureWebServer(String ksFileName, String ksPasswd, String kePasswd)
   {
      this.ksFileName = ksFileName;
      this.ksPasswd   = ksPasswd;
      this.kePasswd   = kePasswd;
   }
   
   /**
    * Construct a SSL Context Factory for HTTPS.
    * <p>
    * This method must be overridden if an SSL connector is required.
    * 
    * @return  The <code>SslContextFactory</code> instance.
    * 
    * @throws  Exception
    *          If any error conditions occur.
    */
   @Override
   protected SslContextFactory getSslContextFactory()
   throws Exception
   {
      try
      {
         keyStore = KeyStore.getInstance("JKS");
      }
      
      catch (KeyStoreException kse)
      {
         LOG.severe(String.format("JKS KeyStore cannot be initialized (%s).", kse.toString()));
         
         return null;
      }
      
      SSLHelper.ErrorCode rc = SSLHelper.loadKeyStoreFromFile(keyStore, ksFileName, ksPasswd);
      
      if (rc != SSLHelper.ErrorCode.NO_ERROR)
      {
         LOG.severe(String.format("KeyStore load failure (%s).", rc.toString()));
         
         return null;
      }
      
      Object[] result = new Object[1];
      
      rc = SSLHelper.initKeyManagers(keyStore, kePasswd, result);
      
      if (rc != SSLHelper.ErrorCode.NO_ERROR)
      {
         LOG.severe(String.format("KeyManager[] init failure (%s).", rc.toString()));
         
         return null;
      }
      
      km = (KeyManager[]) result[0];
      
      SSLContext ctx = null;
      
      try
      {
         ctx = SSLContext.getInstance("TLS");
         ctx.init(km, null, null);
      }
      
      catch (NoSuchAlgorithmException nsa)
      {
         LOG.severe(String.format("SSLContext 'TLS' cannot be instantiated (%s).",
                                  nsa.toString()));
         return null;
      }
      catch (KeyManagementException kme)
      {
         LOG.severe(String.format("SSLContext cannot be initialized (%s).", kme.toString()));
         return null;
      }
      
      SslContextFactory sslContextFactory = new SslContextFactory.Server();
      sslContextFactory.setSslContext(ctx);
      
      return sslContextFactory;
   }
}