Class CertManager

java.lang.Object
org.bzdev.ejws.CertManager

public abstract class CertManager extends Object
Certificate Manager.

A certificate manager is an alternative to EmbeddedWebServer.SSLSetup and, in addition to configuring an EmbeddedWebServer for HTTPS, a certificate manager automatically creates certificates and automatically renews them.

Callers should used the methods newInstance() or newInstance(String) to create an instance of this class. When an argument is provided, it is either the fully-qualified class name of the desired certificate manager, the string "default" for a certificate manager that will provide a self-signed certificate, or the string "external" if another process manages the keystore. When newInstance(), the first instance found using the Java service loader is returned and if there are no such instances, an instance of the default certificate manager is returned. To configure the instance, use the methods

  • setCertName(String). This provides an identifier to name a certificate. Some instances require this.
  • setDomain(String). This provides the domain name used in a certificate.
  • setEmail(String). This provides an email address used to contact a user for administrative purposes (e.g., if a certificate is about to expire).
  • setTimeOffset(int). This provides a time offset in seconds from midnight and is used to schedule checks for expired certificates at a time at which the server is not likely to be busy: the server has to be stopped temporarily to install new certificates.
  • setInterval(int). This provides an interval in days between certificate renewal attempts. A certificate will not be renewed if it is not close to expiring. If set to zero, the value will be treated as one minute, which is useful for testing but not for actual use.
  • setStopDelay(int). This provides the time in seconds to wait before fully shutting down a server when necessary to renew certificates.
  • setProtocol(String). This provides the HTTPS protocol (e.g., SSL or TLS).
  • setKeystoreFile(File). This provides a keystore file that will be used to store certificates using the alias "servercert". If the file does not exist, a new one will be created with a certificate.
  • setTruststoreFile(File). This provides a trust store file to allow the user to specify additional root certificates. It may be null if no trust store is desired.
  • setKeystorePW(char[]). This provides the store password for a keystore as specified by keytool. The default password is "changeit".
  • setKeyPW(char[]). This provides the key password for a keystore as specified by keytool. The default password is the 'store' password.
  • setTruststorePW(char[]). This provides the store password for the trust store.
  • setConfigurator(EmbeddedWebServer.Configurator). This sets an SSL Configurator as specified by EmbeddedWebServer.SSLSetup.configurator(EmbeddedWebServer.Configurator).
  • setTracer(Appendable). This provides an Appendable for tracing/logging.
  • setCertTrace(boolean). This indicates if new certificates should be be printed or not an Appendable for tracing has been configured.
  • setHelper(EmbeddedWebServer). This provides a 'helper' HTTP server that some certificate managers require. While these certificate managers will create such a server, one created with this method can run continuously.
These methods return the CertManager on which they are called so that one can write code such as
 CertManager cm = CertManager.newInstance()
   .setInterval(7)
   .setTimeOffset(4*3600)
   ...
 

The newInstance methods use a ServiceLoader to create instances of CertManager. Each must contain a zero argument constructor and implement the following methods:

A provider may optionally implement the method providerName() to provide a name for a manager that is more mnemonic than its class name, the method configureHelper(EmbeddedWebServer) to configure an HTTP server (that is not running) for use by the provider, and the method helperPort() to indicate the port on which an HTTP server should run, with 0 indicating that such a server is not needed.

As usual, the module-info file for a subclass SUBCLASS should contain the line

     provides org.bzdev.ejws.CertManager with SUBCLASS;
 
(using the fully-qualified name for SUBCLASS) and the META-INF/services directory in the JAR file should contain a file named org.bzdev.ejws.CertManager whose contents also include
 SUBCLASS
 
(Tests indicate that some [all?] versions of Java will not recognize service providers found on the class path if a META-INF/services entry does not exist, so while redundant, including both is safer.)
  • Constructor Details

    • CertManager

      public CertManager()
  • Method Details

    • setMode

      public CertManager setMode(CertManager.Mode mode)
      Set this certificate manager's mode. This method should be used only when debugging or during preliminary testing.

      If not called, the default value is CertManager.Mode.NORMAL.

      Parameters:
      mode - the mode; the default if null
      Returns:
      this certificate manage
      See Also:
    • getMode

      public CertManager.Mode getMode()
      Get the current mode.
      Returns:
      the mode
    • alwaysCreate

      public boolean alwaysCreate()
      Determine if certificates should always be created instead of being reused until they are close to expiring. The default is false.
      Returns:
      true if a certificate should always be created; false otherwise
    • alwaysCreate

      public CertManager alwaysCreate(boolean mode)
      Set if certificates should always be created instead of being reused until they are close to expiring. The default is false.

      This method's primary use is for testing so that any code written to renew a certificate is run as soon as a check for a renewal is made.

      Parameters:
      mode - true if a certificate should always be created; false otherwise
      Returns:
      this certificate manage
    • newInstance

      public static CertManager newInstance()
      Return a new instance of CertManager. The instance returned will preferentially be the first one provided by a service loader. If the server loader cannot find an instance, an instance of the default certificate manager will be returned.
      Returns:
      a new instance of CertManager.
    • providerNames

      public static Set<String> providerNames()
      Get the names of each available certificate manager. A name is either "default" or the fully qualified class name of a certificate manager. A manager may be listed twice if it explicitly specifies a name. Explicitly specified names may be shared by more than one certificate manager.
      Returns:
      the names of the certificate managers.
    • newInstance

      public static CertManager newInstance(String providerName)
      Return a new instance of a certificate manager given its name.
      Parameters:
      providerName - "default" for the default provider, "external" if another process manages certificats, or the fully qualified class name for the desired instance, a a provider name; or null for the first one available, excluding "default" and "external"
    • setTracer

      public CertManager setTracer(Appendable tracer)
      Set an Appendable to log various events.
      Parameters:
      tracer - an Appendable used to log events; null to disable logging
      Returns:
      this CertManager
    • getTracer

      protected Appendable getTracer()
      Get the current Appendable used for tracing.
      Returns:
      the Appendable; null if there is none
    • setCertName

      public CertManager setCertName(String name)
      Set the certificate name. A certificate name is an identifier used to provide a readable name for a certificate. This may be used as part of a file name in some implementations.
      Parameters:
      name - the name.
      Returns:
      this CertManager
    • getCertName

      public String getCertName()
      Get the certificate name.
      Returns:
      the certificate name; null if there is none
    • setDomain

      public CertManager setDomain(String domain)
      Set the domain name for a server. This will typically be the CN (Common Name) portion of a certificate's distinguished name.
      Parameters:
      domain - the domain name (typically fully qualified or "localhost" for testing)
      Returns:
      this CertManager
    • getDomain

      public String getDomain()
      Get the domain name for a server.
      Returns:
      the domain name
    • setEmail

      public CertManager setEmail(String email)
      Set an email address for administrative emails. This may be used for purposes such as notifications that a certificate is about to expire.
      Parameters:
      email - the email address
      Returns:
      this CertManager
    • getEmail

      public String getEmail()
      Get the email address.
      Returns:
      the email address
    • providerName

      public String providerName()
      Optional print name for a provider. The default name for a provider is its fully qualified class name. This method provides an alternate name. It may not be unique and may represent groups of providers. Providers that use certbot should override this method to return the string "certbot". The names "default" and "external" are reserved and must not be used as new provider names.
      Returns:
      the provider name; null if one is not explicitly provided
    • helperPort

      public int helperPort()
      Determine if a certificate manager needs an HTTP server to create a certificate, providing that server's TCP port. For example, some implementations use the ACME protocol to obtain a certificate and use a server running HTTP on port 80 for that purpose. The default implementation returns 0, indicating that a server is not needed. If this method returns a non-zero value and setHelper(EmbeddedWebServer) was not called, a provider's implementation is expected to create a server running HTTP using the port returned by this method.
      Returns:
      the TCP port if a web server is needed; 0 otherwise
    • configureHelper

      protected void configureHelper(EmbeddedWebServer helper)
      Configure a helper HTTP server for use with this certificate manager. The default implementation of this method does nothing and should be overridden by providers such as ones that implement the ACME protocol, which requires a specific configuration for a server.

      This method will be called by setHelper(EmbeddedWebServer) when all of the following are true:

      Parameters:
      helper - the helper HTTP server
    • requestCertificate

      protected abstract void requestCertificate()
      Request a certificate. When this method is called, the certificate should be placed in a keystore specified by setKeystoreFile(File) with an alias "servercert". An existing certificate should be returned unless it is about to expire, and if there is none, a new certificate should be created. This method may return before the operation is complete.

      Some providers of this class (e.g., ones using the ACME protocol) require a server running HTTP on a specified port. In this case, requestCertificate() should call getHelper() and if the result is not null, use that server. If that server is not running, requestCertificate() should ensure that any necessary prefixes have been added.

      If this certificate manager needs a helper and getHelper() returns null, this method must create the helper, configure it, start it, and shut it down before exiting.

    • certificateRequestStatus

      protected abstract boolean certificateRequestStatus()
      Determine the status of a previously issued call to requestCertificate(). If the status is unknown, this method must block until the status can be determined.
      Returns:
      true if a certificate is available; false otherwise
    • requestRenewal

      protected abstract void requestRenewal()
      Request that a certificate be renewed. If a new certificate is available, this method must arrange for renewalRequestStatus() to return true. This method and renewalRequestStatus() are called from different threads.

      If this certificate manager needs a helper and getHelper() returns null, this method must create the helper, configure it, start it, and shut it down before exiting.

    • renewalRequestStatus

      protected abstract boolean renewalRequestStatus() throws InterruptedException
      Determine the status of a previously issued call to requestRenewal() when that method generates a new certificate. This method should normally block until it will return true. It, and requestRenewal(), are called from different threads.
      Returns:
      true if a new certificate is available; false if there was an error.
      Throws:
      InterruptedException
    • setTimeOffset

      public CertManager setTimeOffset(int offset)
      Set the time offset. This is the time of the day in seconds at which attempts to renew certificates will be made. Time is measured from midnight using the server's time zone. The number of days between renewal attempts are set by setInterval(int).

      If not called, the default value is 0.

      Parameters:
      offset - the time offset in seconds
      Returns:
      this CertManager
    • getTimeOffset

      public int getTimeOffset()
      Get the time offset. This is the time of the day in seconds at which attempts to renew certificates will be made. Time is measured from midnight using the server's time zone. The number of days between renewal attempts are set by setInterval(int).
      Returns:
      the time offset in seconds.
    • setInterval

      public CertManager setInterval(int interval)
      Set the number of days between attempts to renew certificates.

      If not called, the default value is 7.

      Parameters:
      interval - the interval in days.
      Returns:
      this CertManager
    • getInterval

      public int getInterval()
      Get the number of days between attempts to renew certificates.
      Returns:
      the interval in days
    • setStopDelay

      public CertManager setStopDelay(int stopDelay)
      Set the delay for stopping a server. When EmbeddedWebServer.stop(int) is called, new requests are rejected immediately, and the delay indicates how long to wait for existing requests to be processed.

      If not called, the default value is 5.

      Parameters:
      stopDelay - the delay in seconds
      Returns:
      this CertManager
    • getStopDelay

      public int getStopDelay()
      Get the delay for stopping a server. When EmbeddedWebServer.stop(int) is called, new requests are rejected immediately, and the delay indicates how long to wait for existing requests to be processed.
      Returns:
      the delay in seconds
    • setTimeZone

      public CertManager setTimeZone(String timezone)
      Set the time zone given a time-zone ID. The Java class TimeZone provides a method to list the available time zone IDs. If the time zone ID is not recognized, the time zone will be set to GMT.

      If not called, the default value is the system default time zone.

      Parameters:
      timezone - the time zone ID (e.g, UTC or America/Los_Angeles); null or an empty string for the system default
      Returns:
      this CertManager
      See Also:
    • setTimeZone

      public CertManager setTimeZone(TimeZone timezone)
      Set the time zone.
      Parameters:
      timezone - the time zone ID (e.g, UTC or America/Los_Angeles); null for the system default
      Returns:
      this CertManager
    • getTimeZone

      public String getTimeZone()
      Get the time-zone ID.
      Returns:
      the time-zone ID for this object
    • getInitialWaitMillis

      public long getInitialWaitMillis()
      Get the waiting time in milliseconds from when a server starts to the first time at which an attempt to renew a certificate is made.
      Returns:
      the time interval in milliseconds
    • setCertTrace

      public CertManager setCertTrace(boolean certTrace)
      Set whether or not certificates should be printed in traces
      Parameters:
      certTrace - true if certificates should be printed; false otherwise
      Returns:
      this CertManager
    • getIntervalMillis

      public long getIntervalMillis()
      Get the time interval between attempts to renew certificates.
      Returns:
      the time interval in milliseconds
    • setProtocol

      public CertManager setProtocol(String protocol)
      Set the protocol for the server to use
      Parameters:
      protocol - the protocol (e.g., SSL or TLS) for HTTPS; null for HTTP
      Returns:
      this CertManager
    • getProtocol

      public String getProtocol()
      Set the protocol for the server to use.
      Returns:
      the protocol (e.g., SSL or TLS) for HTTPS; null for HTTP
    • setKeystoreFile

      public CertManager setKeystoreFile(File file)
      Set the file for a keystore. If the file does not exist, requests to get a certificate will create the file.
      Parameters:
      file - the keystore file; null if there is no keystore
      Returns:
      this CertManager
    • getKeystoreFile

      public File getKeystoreFile()
      Get the file for a keystore. If the file does not exist, requests to get a certificate will create the file.
      Returns:
      the file; null if there is no keystore
    • setTrustManagers

      public CertManager setTrustManagers(TrustManager[] tms) throws IllegalStateException
      Provide trust managers.
      Parameters:
      tms - the trust managers; null too cancel
      Returns:
      this object
      Throws:
      IllegalStateException - if a {#link #t\setTrusstoreFile} was called with a non-null value
      See Also:
    • setTruststoreFile

      public CertManager setTruststoreFile(File file) throws IllegalStateException
      Provide a file containing a trust store.
      Parameters:
      file - a file containing a trust store; null to cancel
      Returns:
      this object
      Throws:
      IllegalStateException - if trustManagers has been called with a non-null value
      See Also:
    • setKeystorePW

      public CertManager setKeystorePW(char[] pw)
      Set the "store" password for a keystore. The default password is "changeit".
      Parameters:
      pw - the password; null for the default
      Returns:
      this CertManager
    • getKeystorePW

      protected char[] getKeystorePW()
      Get the "store" password for a keystore.
      Returns:
      the password; null if there is none
    • setKeyPW

      public CertManager setKeyPW(char[] pw)
      Set the key password for a keystore.
      Parameters:
      pw - the password; null to use the store password
      Returns:
      this CertManager
      See Also:
    • getKeyPW

      protected char[] getKeyPW()
      Get the key password for a keystore.
      Returns:
      the password; the keystore password if no key password has been explicitly provided
    • setTruststorePW

      public CertManager setTruststorePW(char[] pw)
      Set the "store" password for a truststore.
      Parameters:
      pw - the password; null if there is none
      Returns:
      this CertManager
    • getTruststorePW

      protected char[] getTruststorePW()
      Set the "store" password for a truststore.
      Returns:
      pw the password; null if there is none
    • setConfigurator

      public CertManager setConfigurator(EmbeddedWebServer.Configurator c)
      Set the SSL configurator. Configurators are instance of the functional interface EmbeddedWebServer.Configurator, and will typically be provided by a lambda expression that takes two arguments: an instance of SSLContext and an instance of HttpsParameters. These two arguments are provided by the HttpsServer implementation.
      Parameters:
      c - the configurator
      Returns:
      this CertManager
    • getHelper

      protected EmbeddedWebServer getHelper()
      Get a helper web server. Certificate authorities such as Lets-Encrypt use the ACME protocol for managing certificates ( RFC 8555), and these may make use of a separate web server using HTTP instead of HTTPS and typically running on port 80. This method returns an EmbeddedWebServer that can be used for such purposes. When provided, the method requestCertificate() is expected to start the helper if it is not already running and will start the helper after adding any prefixes needed as part of the process of obtaining a certificate.

      When this method returns null, requestCertificate() and requestRenewal() are expected to create a helper if needed, but will usually shut this helper down before returning.

      Returns:
      the web server; null if none is provided
    • setHelper

      public CertManager setHelper(EmbeddedWebServer helper)
      Set a helper web server. Certificate authorities such as Lets-Encrypt use the ACME protocol for managing certificates ( RFC 8555), and these may make use of a separate web server using HTTP instead of HTTPS and running on port 80. This method allows the caller to provide an EmbeddedWebServer that can be used for such purposes, with the added benefit of configuring additional prefixes to handle the case where a client is given a URL whose scheme is HTTP instead of HTTPS.

      If all of the following are true

      1. the argument to this method is not null,
      2. helperPort() returns a non-zero value,
      3. the helper server is not an HTTPS server,
      4. the helper server is not currently running,
      then the helper will be configured, typically adding prefixes needed for it to operate as a helper, and the helper will be started.

      If a server is configured with this CertManager and that server is shut down, the helper will also be shut down and cannot be reused. As a result, a CertManager that provides a helper should be used with only a single EmbeddedWebServer. Certificate manager providers should not try to start a helper that is already running. It is a good practice to let the provider start the helper.

      Parameters:
      helper - the embedded web server to use; null (the default) if none is provided
      Returns:
      this CertManager
      See Also:
    • getSetup

      public EmbeddedWebServer.SSLSetup getSetup() throws IOException
      Get a configured instance of EmbeddedWebServer.SSLSetup. Various methods provided by this class duplicate those provided by EmbeddedWebServer.SSLSetup.

      Calling this method will also create keystore file and a certificate if one is not already available.

      Returns:
      a configured instance EmbeddedWebServer.SSLSetup
      Throws:
      IOException
    • isMonitoring

      public boolean isMonitoring()
      Test if certificates ares being monitored.
      Returns:
      true if certificates are being monitored; false otherwise
    • startMonitoring

      public void startMonitoring(EmbeddedWebServer ews)
      Start monitoring certificates for a server
      Parameters:
      ews - the server whose certificates are to be monitored
    • stopMonitoring

      public void stopMonitoring()
      Stop monitoring certificates for a server.