ProcessBuilderOptions.java
/*
** Module : ProcessBuilderOptions.java
** Abstract : store P2J process parameters read from directory.
**
** Copyright (c) 2014-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------Description----------------------------------
** 001 CA 20140206 First version.
** 002 MAG 20140224 Add support for output file.
** 003 CA 20160205 SecurityManager.getEncryptedKeyStore now returns a function which is cached
** for each thread, and will be non-null only if the thread has proper access to
** this SecurityManager API.
** 004 SBI 20171116 Changed to be according to EncryptedKeyStoreFunction.
** 005 CA 20191211 When spawning a Java process programmatically, allow the caller to pass
** environment options specific to that call (beside any jvmArgs configured in
** the directory).
** 006 GBB 20230825 SecurityManager certificate methods calls updated.
** 007 GBB 20240709 Hard-coded config names replaced by ConfigItem constants. Redundant methods removed.
** 008 GBB 20240718 Config read implemented in concrete class BaseClientBuilderOptions.
** 009 GBB 20241010 Always set validateCertificate to true.
*/
/*
** 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.main;
import java.util.*;
import com.goldencode.p2j.main.ServerKeyStore.*;
import com.goldencode.p2j.security.SecurityManager;
import com.goldencode.p2j.security.SecurityManager.*;
import com.goldencode.p2j.util.*;
import com.goldencode.p2j.util.Utils.DirScope;
import com.goldencode.util.*;
/**
* The parameters stored inside this structure are read from directory on server start-up
* and are used as default parameters to create and spawn a web client process.
* <p>
* The container node is named {@link ConfigItem#CLIENT_CONF_CONTAINER} and the first child of these nodes is
* used:
* <ol>
* <li>server/<server-id>/runtime/<process-id>/</li>
* <li>server/<server-id>/runtime/default/</li>
* <li>server/<server-id>/</li>
* <li>server/default/</li>
* </ol>
*/
class ProcessBuilderOptions
implements ClientBuilderOptions
{
/**
* Thread-local cache of the key store function obtained from {@link SecurityManager}.
* This may be <code>null</code> if the thread doesn't have the proper security context to
* access the function.<p>
* This is set as a thread-local variable instead of a static field to not expose the worker
* in SecurityManager.CertificateSecurityManager#getEncryptedKeyStore() which
* returns the private key store to other threads which may not have a server context. It is
* initialized only once per thread, and only if the thread has access to the
* SecurityManager.CertificateSecurityManager#certificateSm#getEncryptedKeyStore() API.
*/
private static final ThreadLocal<EncryptedKeyStoreFunction> encryptedKeyStoreWorker = new ThreadLocal<>();
/** The alias in the process keystore. */
private final String processAlias;
/** The alias in the truststore. */
private final String truststoreAlias;
/** The keystore password. */
private final String keystorePassword;
/** The keyentry password. */
private final String keyentryPassword;
/** The truststore password. */
private final String truststorePassword;
/** Flag indicating if the certificate must be validated. */
private final boolean validateCertificate;
/** The serialized process keystore. */
private final byte[] processKeystore;
/** The serialized truststore. */
private final byte[] truststore;
/**
* All the subject IDs associated with this builder or <code>null</code> to use the context's subject IDs.
*/
private final String[] accountIds;
/** The name of the output file. */
private final String outputToFile;
/** P2J process name */
private final String process;
/** Base options. */
private final BaseClientBuilderOptions baseOptions;
/**
* Initialize. Read all configuration parameters from directory.
*
* @param process
* The process subject ID.
* @param env
* Map of additional environment properties, in the <code>key=value</code> form.
*/
public ProcessBuilderOptions(String process, Map<String, String> env)
{
SecurityManager sm = SecurityManager.getInstance();
this.accountIds = sm.getAccountIds(process);
this.process = process;
String ksPassword = RandomWordGenerator.create();
String kePassword = RandomWordGenerator.create();
String procAlias = sm.getAccountAlias(process);
this.validateCertificate = true;
if (encryptedKeyStoreWorker.get() == null)
{
encryptedKeyStoreWorker.set(sm.certificateSm.getEncryptedKeyStore());
}
if (encryptedKeyStoreWorker.get() != null)
{
this.processKeystore = encryptedKeyStoreWorker.get().getEncryptedKeyStore(procAlias,
ksPassword,
kePassword,
Store.TRUST_STORE);
}
else
{
this.processKeystore = null;
}
if (this.processKeystore == null)
{
this.processAlias = null;
this.keystorePassword = null;
this.keyentryPassword = null;
}
else
{
this.processAlias = procAlias;
this.keystorePassword = ksPassword;
this.keyentryPassword = kePassword;
}
this.truststorePassword = RandomWordGenerator.create();
this.truststoreAlias = sm.getServerAlias();
this.truststore = sm.certificateSm.getEncryptedTrustStore(truststorePassword);
this.outputToFile = ConfigItem.OUTPUT_TO_FILE.read(null, DirScope.BOTH, accountIds);
this.baseOptions = new BaseClientBuilderOptions(env)
{
/**
* A convenience method to read the client config with the specified default value.
*
* @param clientConfig
* The client config to read.
* @param defaultValue
* The default value returned if no value found in directory.
* @param <T>
* The type of the client config.
*
* @return The client config value as read from directory.
*/
@Override
<T> T read(ConfigItem<T> clientConfig, T defaultValue)
{
return clientConfig.read(null, DirScope.BOTH, defaultValue, null, null, accountIds);
}
/**
* A convenience method to read the client config with the specified default value.
*
* @param clientConfig
* The client config to read.
* @param defaultValue
* The default value returned if no value found in directory.
* @param placeholderValue
* The value to replace the placeholder in the directory node name for the config.
* @param <T>
* The type of the client config.
*
* @return The client config value as read from directory.
*/
@Override
<T> T read(ConfigItem<T> clientConfig, T defaultValue, String placeholderValue)
{
return clientConfig.read(null, DirScope.BOTH, defaultValue, null, placeholderValue, accountIds);
}
/**
* Reads and returns the value of clientConfig/cfgOverrides.
*
* @param defaultValue
* The default value returned if no value found in directory.
*
* @return The cfgOverrides value.
*/
@Override
String readCfgOverrides(String defaultValue)
{
return read(ConfigItem.CFG_OVERRIDES, defaultValue);
}
};
}
/**
* Returns the base client options.
*
* @return The base client options.
*/
@Override
public BaseClientBuilderOptions getBaseOptions()
{
return baseOptions;
}
/**
* Getter for the {@link #processAlias}.
*
* @return See above.
*/
public String getProcessAlias()
{
return processAlias;
}
/**
* Getter for the {@link #truststoreAlias}.
*
* @return See above.
*/
public String getTruststoreAlias()
{
return truststoreAlias;
}
/**
* Getter for the {@link #keystorePassword}.
*
* @return See above.
*/
public String getKeystorePassword()
{
return keystorePassword;
}
/**
* Getter for the {@link #keyentryPassword}.
*
* @return See above.
*/
public String getKeyentryPassword()
{
return keyentryPassword;
}
/**
* Getter for the {@link #truststorePassword}.
*
* @return See above.
*/
public String getTruststorePassword()
{
return truststorePassword;
}
/**
* Getter for the {@link #validateCertificate}.
*
* @return See above.
*/
public boolean isValidateCertificate()
{
return validateCertificate;
}
/**
* Getter for the {@link #processKeystore}.
*
* @return See above.
*/
public byte[] getProcessKeystore()
{
return processKeystore;
}
/**
* Getter for the {@link #truststore}.
*
* @return See above.
*/
public byte[] getTruststore()
{
return truststore;
}
/**
* Get the output file template.
*
* @return The the output file template string.
*/
public String getOutputToFile()
{
return outputToFile;
}
/**
* Get P2J process name.
*
* @return The P2J process name.
*/
public String getProcess()
{
return process;
}
}