Contents
Using the Application Template Application Block
Introduction
Instead of using the Platform SDK Commons Library to configure TLS connections with hard-coded values, you can use the Platform SDK Application Template Application Block to retrieve configuration objects from Configuration Server which contain parameters that are used to configure your TLS settings.
The steps do accomplish this are as follows:
- Parse a configuration object
- Create a TLSConnectionConfiguration object for the configuration object
- Customize your TLSConnectionConfiguration object:
- Add callback handlers
- For clients, set the expected host names for primary and backup servers
- Create SSLContext and SSLExtendedOptions objects based on your TLSConnectionConfiguration object
- Use your SSLContext and SSLExtendedOptions objects to create Endpoints and/or WarmStandbyConfiguration objects
- Use your Endpoints and/or WarmStandbyConfiguration objects to create Protocol instances
The sections below describe these steps in more detail. If you plan on using this method to configure TLS settings, be sure that related application objects in Configuration Manager have been configured with TLS parameters.
Note: If you aren't familiar with TLS configuration settings then please read Using the Platform SDK Commons Library to gain a better understanding of what is required.
Parsing Configuration Objects
The Platform SDK Application Template has a helper class, TLSConfigurationParser, which makes it easy to extract TLS parameters from Configuration Server. Taken together, the TLSConfigurationParser, ClientConfigurationHelper, and ServerConfigurationHelper classes cover all of the connection-related options found in Configuration Server. They also provide other useful functionality.
TLSConfigurationParser has two methods:
public static void parseClientTLSConfiguration( IGApplicationConfiguration appConfig, IGApplicationConfiguration.IGAppConnConfiguration connConfig, ITLSConnectionConfiguration config);
and
public static void parseServerTLSConfiguration( IGApplicationConfiguration appConfig, IGApplicationConfiguration.IGPortInfo portConfig, ITLSConnectionConfiguration config);
Both of these methods require configuration objects and an ITLSConnectionConfiguration instance as parameters. The ITLSConnectionConfiguration instance is provided with setter methods that you can use to populate its TLS parameters.
For example:
// Client side // Prepare configuration objects String clientAppName = "<my-app-name>"; CfgAppType targetServerType = CfgAppType.CFGTServer; CfgApplication cfgApplication = confService.retrieveObject( CfgApplication.class, new CfgApplicationQuery(clientAppName)); GCOMApplicationConfiguration appConfiguration = new GCOMApplicationConfiguration(cfgApplication); IGApplicationConfiguration.IGAppConnConfiguration connConfig = appConfiguration.getAppServer(targetServerType); // Parse TLS parameters ITLSConnectionConfiguration tlsConfiguration = new TLSConnectionConfiguration(); TLSConfigurationParser.parseClientTLSConfiguration( appConfiguration, connConfig, tlsConfiguration); // At this point, tlsConfiguration contains TLS parameters read from // configuration objects
// Server side // Prepare configuration objects String serverAppName = "<my-app-name>"; String portID = "secure"; CfgApplication cfgApplication = confService.retrieveObject( CfgApplication.class, new CfgApplicationQuery(serverAppName)); GCOMApplicationConfiguration appConfiguration = new GCOMApplicationConfiguration(cfgApplication); IGApplicationConfiguration.IGPortInfo portConfig = appConfiguration.getPortInfo(portID); // Parse TLS parameters ITLSConnectionConfiguration tlsConfiguration = new TLSConnectionConfiguration(); TLSConfigurationParser.parseServerTLSConfiguration( appConfiguration, portConfig, tlsConfiguration); // At this point, tlsConfiguration contains TLS parameters read from // configuration objects
Customizing TLS Configuration
After a TLSConnectionConfiguration object has been populated from configuration objects, it requires further customization.
Note: The TLSConfiguration, TLSConfigurationHelper and TLSConfigurationParser classes in the Platform SDK Commons Connection library are only used internally for TLS upgrade connections, and currently are not intended for any other use. For custom TLS configuration, please use classes from the Application Template Application Block.
Setting Callback Handlers for Password Retrieval
Callback handlers for password retrieval must be set explicitly and cannot be configured externally. This applies to both client and server applications.
Note: Callback handlers for password retrieval must always be set—even if they are not going to be used—because some security providers require them. If you do not require password retrieval then Platform SDK provides a dummy class that can be used instead of creating a custom callback handler.
Here is how to set callback handlers in the ITLSConnectionConfiguration object for password retrieval:
// Passwords are not used, so set dummies: tlsConfiguration.setKeyStoreCallbackHandler( new DummyPasswordCallbackHandler()); tlsConfiguration.setTrustStoreCallbackHandler( new DummyPasswordCallbackHandler());
// Real password is needed: tlsConfiguration.setKeyStoreCallbackHandler(new CallbackHandler() { public void handle(Callback[] callbacks) { char[] password = new char[] { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; for (Callback c : callbacks) { if (c instanceof PasswordCallback) { ((PasswordCallback) c).setPassword(password); } } } } );
Setting the Expected Host Name
Specifying the expected host name is not always a straightforward process. When you are configuring TLS on the client side in particular, note that the expected host names for primary and backup connections are usually (although not always) different. Users may also choose to use IP addresses instead of DNS host names, or to use DNS names with wildcards.
No matter how these names have been set up, the expected host name must match one of names specified in the server's certificate. In extreme cases, these names may not relate to the actual host name at all. To allow for these kinds of situations, Platform SDK does not attempt to set the expected host name for you. You will have to write your own code for this purpose.
The following sample code shows how to set the expected server name to the actual host name of the target server:
// Client side // Prepare configuration objects String clientAppName = "<my-app-name>"; CfgAppType targetServerType = CfgAppType.CFGTServer; CfgApplication cfgApplication = confService.retrieveObject( CfgApplication.class, new CfgApplicationQuery(clientAppName)); GCOMApplicationConfiguration appConfiguration = new GCOMApplicationConfiguration(cfgApplication); IGApplicationConfiguration.IGAppConnConfiguration connConfig = appConfiguration.getAppServer(targetServerType); // TLS-specific part IGApplicationConfiguration.IGServerInfo primaryServer = connConfig.getTargetServerConfiguration().getServerInfo(); IGApplicationConfiguration.IGServerInfo backupServer = primaryServer.getBackup().getServerInfo(); tlsConfiguration.setExpectedHostname(primaryServer.getHost().getName()); // Or: tlsConfiguration.setExpectedHostname(backupServer.getHost().getName());
Creating SSLContext Objects
The Platform SDK Application Template has a helper class, TLSConfigurationHelper, which creates SSLContext and SSLExtendedOptions objects by using information from a TLSConnectionConfiguration object.
TLSConfigurationHelper has two methods:
public static SSLContext createSSLContext( ITLSConnectionConfiguration config);
and
static SSLExtendedOptions createSSLExtendedOptions( ITLSConnectionConfiguration config);
The createSSLContext() method determines the security provider type, creates the necessary key store objects, a key manager, and a trust manager, and then wraps it all into an SSLContext object.
The createSSLExtendedOptions() method does not contain any logic. It just creates a new SSLExtendedOptions object containing the exact parameters taken from the TLSConnectionConfiguration object.
Here are samples of how to use these methods:
// TLS preparation section follows ITLSConnectionConfiguration tlsConfiguration = new TLSConnectionConfiguration(); TLSConfigurationParser.parseClientTLSConfiguration( appConfiguration, connConfig, tlsConfiguration); SSLContext sslContext = TLSConfigurationHelper.createSSLContext(tlsConfiguration); SSLExtendedOptions sslOptions = TLSConfigurationHelper.createSSLExtendedOptions(tlsConfiguration);
Configuring TLS for Client Connections
Platform SDK has a helper class, ClientConfigurationHelper, that makes it easier to prepare connections for client applications. This class has the following methods:
public static Endpoint createEndpoint( IGApplicationConfiguration appConfig, IGAppConnConfiguration connConfig, IGApplicationConfiguration targetServerConfig);
public static Endpoint createEndpoint( IGApplicationConfiguration appConfig, IGAppConnConfiguration connConfig, IGApplicationConfiguration targetServerConfig, boolean tlsEnabled, SSLContext sslContext, SSLExtendedOptions sslOptions);
public static WarmStandbyConfiguration createWarmStandbyConfig( IGApplicationConfiguration appConfig, IGAppConnConfiguration connConfig);
public static WarmStandbyConfiguration createWarmStandbyConfig( IGApplicationConfiguration appConfig, IGAppConnConfiguration connConfig, boolean primaryTLSEnabled, SSLContext primarySSLContext, SSLExtendedOptions primarySSLOptions, boolean backupTLSEnabled, SSLContext backupSSLContext, SSLExtendedOptions backupSSLOptions);
Two of these methods simply accept TLS-specific parameters and pass them through to the Endpoint and WarmStandbyConfiguration instances being created. A code sample using the createEndpoint() method is shown here:
String clientAppName = "<my-app-name>"; CfgAppType targetServerType = CfgAppType.CFGTServer; CfgApplication cfgApplication = confService.retrieveObject( CfgApplication.class, new CfgApplicationQuery(clientAppName)); GCOMApplicationConfiguration appConfiguration = new GCOMApplicationConfiguration(cfgApplication); IGAppConnConfiguration connConfig = appConfiguration.getAppServer(targetServerType); // TLS preparation section follows ITLSConnectionConfiguration tlsConfiguration = new TLSConnectionConfiguration(); TLSConfigurationParser.parseClientTLSConfiguration( appConfiguration, connConfig, tlsConfiguration); // TLS customization code goes here... // As an example, host name verification is turned on IGApplicationConfiguration.IGServerInfo targetServer = connConfig.getTargetServerConfiguration().getServerInfo(); tlsConfiguration.setExpectedHostname(targetServer.getHost().getName()); // Get TLS configuration objects for connection SSLContext sslContext = TLSConfigurationHelper.createSSLContext(tlsConfiguration); SSLExtendedOptions sslOptions = TLSConfigurationHelper.createSSLExtendedOptions(tlsConfiguration); boolean tlsEnabled = true; // TLS preparation section ends Endpoint epTSrv = ClientConfigurationHelper.createEndpoint( appConfiguration, connConfig, connConfig.getTargetServerConfiguration(), tlsEnabled, sslContext, sslOptions); TServerProtocol tsProtocol = new TServerProtocol(epTSrv); tsProtocol.setClientName(clientName); tsProtocol.open();
Configuring Warm Standby
In cases when the target server has a backup in warm standby mode, configuration requires a little extra effort, as shown in the following code sample.
Note: Configuring TLS for primary and backup servers in Warm Standby mode has some specifics that may not be obvious. Primary and backup servers typically share the same settings. Thus, when a server is selected as a backup for another server (the primary server), Configuration Manager copies settings from the primary server to the backup server to make them the same. This is also true of TLS settings, and the same TLSConnectionConfiguration object can be used to configure both the primary and backup connections. On the other hand, primary and backup servers usually reside on different hosts. This means that if a hostname check is used, each of these servers must have different expectedHostname parameter values. This is not hard to do, as the following code sample demonstrates, but it is not always obvious.
String clientAppName = "<my-app-name>"; CfgAppType targetServerType = CfgAppType.CFGStatServer; CfgApplication cfgApplication = confService.retrieveObject( CfgApplication.class, new CfgApplicationQuery(appName)); GCOMApplicationConfiguration appConfiguration = new GCOMApplicationConfiguration(cfgApplication); IGAppConnConfiguration connConfig = appConfiguration.getAppServer(targetServerType); // TLS preparation section follows ITLSConnectionConfiguration tlsConfiguration = new TLSConnectionConfiguration(); TLSConfigurationParser.parseClientTLSConfiguration( appConfiguration, connConfig, tlsConfiguration); IGApplicationConfiguration.IGServerInfo primaryServer = connConfig.getTargetServerConfiguration().getServerInfo(); IGApplicationConfiguration.IGServerInfo backupServer = primaryServer.getBackup().getServerInfo(); // Configure TLS for Primary tlsConfiguration.setExpectedHostname(primaryServer.getHost().getName()); SSLContext primarySSLContext = TLSConfigurationHelper.createSSLContext(tlsConfiguration); SSLExtendedOptions primarySSLOptions = TLSConfigurationHelper.createSSLExtendedOptions(tlsConfiguration); boolean primaryTLSEnabled = true; // Configure TLS for Backup tlsConfiguration.setExpectedHostname(backupServer.getHost().getName()); SSLContext backupSSLContext = TLSConfigurationHelper.createSSLContext(tlsConfiguration); SSLExtendedOptions backupSSLOptions = TLSConfigurationHelper.createSSLExtendedOptions(tlsConfiguration); boolean backupTLSEnabled = true; // TLS preparation section ends WarmStandbyConfiguration wsConfig = ClientConfigurationHelper.createWarmStandbyConfig( appConfiguration, connConfig, primaryTLSEnabled, primarySSLContext, primarySSLOptions, backupTLSEnabled, backupSSLContext, backupSSLOptions); StatServerProtocol statProtocol = new StatServerProtocol(wsConfig.getActiveEndpoint()); statProtocol.setClientName(clientName); WarmStandbyService wsService = new WarmStandbyService(statProtocol); wsService.applyConfiguration(wsConfig); wsService.start(); statProtocol.beginOpen();
Configuring TLS for Servers
Platform SDK has a helper class, ServerConfigurationHelper, that makes it easier to prepare listening sockets for server applications. This class has the following methods:
public static Endpoint createListeningEndpoint( IGApplicationConfiguration application, IGApplicationConfiguration.IGPortInfo portInfo);
public static Endpoint createListeningEndpoint( IGApplicationConfiguration application, IGApplicationConfiguration.IGPortInfo portInfo, boolean tlsEnabled, SSLContext sslContext, SSLExtendedOptions sslOptions);
The overloaded version of the createListeningEndpoint() method accepts TLS parameters and passes them through to the Endpoint object that is being created. The following code sample shows how this is done:
String serverAppName = "<my-app-name>"; String portID = "secure"; CfgApplication cfgApplication = confService.retrieveObject( CfgApplication.class, new CfgApplicationQuery(appName)); GCOMApplicationConfiguration appConfig = new GCOMApplicationConfiguration(cfgApplication); IGApplicationConfiguration.IGPortInfo portConfig = appConfig.getPortInfo(portID); // TLS preparation section follows ITLSConnectionConfiguration tlsConfiguration = new TLSConnectionConfiguration(); TLSConfigurationParser.parseServerTLSConfiguration( appConfiguration, portConfig, tlsConfiguration); // TLS customization code goes here... // As an example, mutual TLS mode is turned on tlsConfiguration.setTLSMutual(true); // Get TLS configuration objects for connection SSLContext sslContext = TLSConfigurationHelper.createSSLContext(tlsConfiguration); SSLExtendedOptions sslOptions = TLSConfigurationHelper.createSSLExtendedOptions(tlsConfiguration); boolean tlsEnabled = true; // TLS preparation section ends Endpoint endpoint = ServerConfigurationHelper.createListeningEndpoint( appConfig, portConfig, tlsEnabled, sslContext, sslOptions); ExternalServiceProtocolListener serverChannel = new ExternalServiceProtocolListener(endpoint); ...