Property value substitution
Property value substitution enables you to achieve the following:
-
Define a configuration that is specific to a single instance.
For example, set the location of the keystore on a particular host.
-
Define a configuration whose parameters vary between different environments.
For example, change hostnames for test, development, and production environments.
Disable certain capabilities on specific servers. For example, disable a database backend and its replication agreement for one set of replicas while enabling it on another set of replicas. This makes it possible to use the same configuration for environments with different data sets.
Property value substitution uses configuration expressions to introduce variables into the server configuration. You set configuration expressions as the values of configuration properties. The effective property values can be evaluated in a number of ways.
Scope of configuration expressions
DS servers only resolve configuration expressions in the DS servers do not resolve configuration expressions anywhere else. DS servers resolve expressions at startup to determine the configuration. DS commands that read the configuration in offline mode also resolve expressions at startup. When you use expressions in the configuration, you must make their values available before starting the server and also when running such commands. |
Configuration expressions share their syntax and underlying implementation with other platform software. Configuration expressions have the following characteristics:
-
To distinguish them from static values, expression tokens are preceded by an ampersand and enclosed in braces.
For example:
&{listen.port}
. The expression token in the example islisten.port
. The.
serves as the separator character. -
You can use a default value in an expression by including it after a vertical bar following the token.
For example, the following expression sets the default listen port value to 1389:
&{listen.port|1389}
. -
A configuration property can include a mix of static values and expressions.
For example, if
hostname
is set todirectory
,&{hostname}.example.com
evaluates todirectory.example.com
. -
You can define nested properties (that is, a property definition within another property definition).
For example, if
listen.port
is set to&{port.prefix}389
, andport.prefix
is set to2
,&{listen.port}
evaluates to2389
. -
You can read the value of an expression token from a file.
For example, if the plaintext password is stored in
/path/to/password.txt
, the following expression resolves to the plaintext password:&{file:/path/to/password.txt}
.You specify the file either by its absolute path, or by a path relative to the DS instance directory. In other words, if the DS instance directory is
/path/to/opendj
, then/path/to/opendj/config/keystore
andconfig/keystore
reference the same file.
DS servers define the following expression tokens by default. You can use these in expressions without explicitly setting their values beforehand:
ds.instance.dir
-
The file system directory holding the instance files required to run an instance of a server.
By default, the files are co-located with the product tools, libraries, and configuration files. You can change the location by using the
setup --instancePath
option.This evaluates to a directory, such as
/path/to/my-instance
. ds.install.dir
-
The file system directory where the server files are installed.
This evaluates to a directory, such as
/path/to/opendj
.
Expression evaluation and order of precedence
You must define expression values before starting the DS server that uses them.
When evaluated, an expression must return the appropriate type for the configuration property.
For example, the listen-port
property takes an integer.
If you set it using an expression, the result of the evaluated expression must be an integer.
If the type is wrong, the server fails to start due to a syntax error.
If the expression cannot be resolved, and there is no default value in the configuration expression, DS also fails to start.
Expression resolvers evaluate expression tokens to literal values.
Expression resolvers get values from the following sources:
Environment variables
You set an environment variable to hold the value.
For example: export LISTEN_PORT=1389
.
The environment variable name must be composed of uppercase characters and underscores. The name maps to the expression token as follows:
-
Uppercase characters are lower cased.
-
Underscores,
_
, are replaced with.
characters.
In other words, the value of LISTEN_PORT
replaces &{listen.port}
in the server configuration.
Java system properties
You set a Java system property to hold the value.
Java system property names must match expression tokens exactly.
In other words, the value of the listen.port
system property replaces &{listen.port}
in the server configuration.
Java system properties can be set in a number of ways.
One way of setting system properties for DS servers is
to pass them through the OPENDJ_JAVA_ARGS
environment variable.
For example: export OPENDJ_JAVA_ARGS="-Dlisten.port=1389"
.
Expressions files
You set a key in a .json
or .properties
file to hold the value.
This optional mechanism is set using the DS_ENVCONFIG_DIRS
environment variable,
or the ds.envconfig.dirs
Java system property.
Keys in .properties
files must match expression tokens exactly.
In other words, the value of the listen.port
key replaces &{listen.port}
in the server configuration.
The following example properties file sets the listen port:
listen.port=1389
JSON expression files can contain nested objects. JSON field names map to expression tokens as follows:
-
The JSON path name matches the expression token.
-
The
.
character serves as the JSON path separator character.
The following example JSON file sets the listen address and listen port:
{
"listen": {
"address": "192.168.0.10",
"port": "1389"
}
}
In other words, the value of the listen/port
field replaces &{listen.port}
in the server configuration.
In order to use expression files, set the environment variable, DS_ENVCONFIG_DIRS
, or the Java system property,
ds.envconfig.dirs
, to a comma-separated list of the directories containing the expression files.
The following constraints apply when using expression files:
-
Although DS browses the directories in the specified order, within a directory DS scans the files in a non-deterministic order.
-
DS reads all files with
.json
and.properties
extensions. -
DS does not scan subdirectories.
-
Do not define the same configuration token more than once in a file, as you cannot know in advance which value will be used.
-
You cannot define the same configuration token in more than one file in a single directory. If the same token occurs in more than one file in a single directory, an error occurs.
-
If the same token occurs once in several files which are located in different directories, the first value that DS reads is used.
The preceding list reflects the order of precedence:
-
Environment variables override system properties, default token settings, and settings in any expression files.
-
System properties override default token settings, and any settings in expression files.
-
If
DS_ENVCONFIG_DIRS
ords.envconfig.dirs
is set, then the server uses settings found in expression files. -
Default token settings (
ds.config.dir
,ds.instance.dir
,ds.install.dir
).
For an embedded DS server, it is possible to change the expression resolvers, in the server configuration.
Use multivalued expressions
A single expression token can evaluate to multiple property values. Such expressions are useful with multivalued properties.
For example, suppose you choose to set a connection handler’s ssl-cipher-suite
property.
Instead of listing cipher suites individually, you use an ssl.cipher.suites
token that takes multiple values.
The following example commands set the token value in the environment, stop the server, use the expression in the LDAP connection handler configuration while the server is offline, and then start the server again:
$ export SSL_CIPHER_SUITES=\
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,\
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,\
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
$ stop-ds --quiet
$ dsconfig \
set-connection-handler-prop \
--offline \
--handler-name LDAPS \
--add ssl-protocol:TLSv1.2 \
--add ssl-cipher-suite:'&{ssl.cipher.suites}' \
--no-prompt
$ start-ds --quiet
Multiple values are separated by commas in environment variables, system properties, and properties files. They are formatted as arrays in JSON files.
Use one of the following alternatives to set the value of the ssl.cipher.suites
token.
In each case, when the server evaluates &{ssl.cipher.suites}
, the result is the following property values:
ssl-cipher-suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
ssl-cipher-suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
ssl-cipher-suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
ssl-cipher-suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
ssl-cipher-suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV
Environment variable
export SSL_CIPHER_SUITES=\
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,\
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,\
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
System property
export OPENDJ_JAVA_ARGS="-Dssl.cipher.suites=\
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,\
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,\
TLS_EMPTY_RENEGOTIATION_INFO_SCSV"
Properties file
ssl.cipher.suites=\
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,\
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,\
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
JSON file
{
"ssl.cipher.suites": [
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV"
]
}
Alternative JSON file that sets ssl.protocol
as well:
{
"ssl": {
"protocol": "TLSv1.2",
"cipher.suites": [
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV"
]
}
}
In order to fully use the settings in this file,
you would have to change the example to include the additional expression:
--add ssl-protocol:'&{ssl.protocol}'
.
Debug expressions
You can debug configuration expressions.
Create a debug target for org.forgerock.config.resolvers
.
The following example demonstrates the process:
$ dsconfig \
create-debug-target \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--publisher-name "File-Based Debug Logger" \
--type generic \
--target-name org.forgerock.config.resolvers \
--set enabled:true \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
$ dsconfig \
set-log-publisher-prop \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--publisher-name "File-Based Debug Logger" \
--set enabled:true \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
$ stop-ds --restart --quiet
When the server starts, it logs debugging messages for configuration expressions. Do not leave debug logging enabled in production systems.