Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve keystore_password when merging env properties #829

Merged
merged 1 commit into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/libertyExtensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,8 @@ The following properties are supported for server configuration.
| timeout | String | 1.0 | Waiting time before the server starts. The default value is 30 seconds. The unit is seconds. Only used with `libertyStart` and `deploy` tasks. | No |
| var | Properties | 3.0 | Inline server variables that are written to the `configDropins/overrides/liberty-plugin-variable-config.xml` file in the server directory. The property name is used for the variable `name`, and the property value is used for the variable `value`.| No|
| verifyAppStartTimeout | int | 2.0 | Wait time for checking message logs for start of all applications installed with the `deploy` task. Only used with the `libertyStart` task. Default value is 0 seconds with no verification. | No |

If Liberty configuration is specified with Gradle properties for the server extension properties of type `Properties`, the above indicated files are created in the target Liberty server. By default there is no merging behavior for the Gradle properties with files located in the `configDirectory` or the specific configuration file parameters such as `bootstrapPropertiesFile`, `jvmOptionsFile` and `serverEnvFile`. However, the `liberty.server.env."var"` Gradle properties can be merged with other configured `server.env` files by setting the `mergeServerEnv` parameter to `true`.

As a special case when `mergeServerEnv` is `false`, an existing `keystore_password` property in the default generated `server.env` file in the target server will be merged in if there is no `serverEnvFile` configured nor `server.env` file located in the `configDirectory`, and the `keystore_password` env var is not defined as a Gradle property.

Original file line number Diff line number Diff line change
Expand Up @@ -886,10 +886,14 @@ abstract class AbstractServerTask extends AbstractLibertyTask {

private String setServerEnvHelper(File envFile, String serverEnvPath, Properties configuredProps) {
if ((server.env != null && !server.env.isEmpty()) || !envProjectProps.isEmpty()) {
if (serverEnvPath != null) {
Properties envPropsToWrite = configuredProps
if (serverEnvPath == null && server.serverEnvFile == null) {
// Do a special case merge but ONLY if there is no server.env file present in configDirectory or specified with serverEnvFile
envPropsToWrite = mergeSpecialPropsFromInstallServerEnvIfAbsent(envFile, configuredProps)
} else if (serverEnvPath != null) {
logger.warn("The " + serverEnvPath + " file is overwritten by inlined configuration.")
}
writeServerEnvProperties(envFile, configuredProps)
writeServerEnvProperties(envFile, envPropsToWrite)
return "inlined configuration"
} else if (server.serverEnvFile != null && server.serverEnvFile.exists()) {
if (serverEnvPath != null) {
Expand All @@ -900,6 +904,32 @@ abstract class AbstractServerTask extends AbstractLibertyTask {
}
}

/**
* Merges envProps with special properties found in envFile, the install (target) server.env. We return a clone/copy of
* envProps, to which any of a list of special properties found in envFile have been added. We give precedence
* to properties already in envProps.
*/
private Properties mergeSpecialPropsFromInstallServerEnvIfAbsent(File envFile, Properties envProps) throws IOException {

String[] specialProps = { "keystore_password" }

// Make a copy to avoid side effects
Properties mergedProps = new Properties()
mergedProps.putAll(envProps)

// From install (target) dir
Properties serverEnvProps = convertServerEnvToProperties(envFile)

for (String propertyName : specialProps) {
if (serverEnvProps.containsKey(propertyName)) {
mergedProps.putIfAbsent(propertyName,serverEnvProps.get(propertyName))
}
}

return mergedProps
}


private Properties convertServerEnvToProperties(File serverEnv) {
Properties serverEnvProps = new Properties();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package io.openliberty.tools.gradle

import org.junit.AfterClass
import org.junit.BeforeClass
import org.junit.Test

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import java.io.BufferedReader;
import java.io.FileReader;


import org.junit.BeforeClass
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runners.MethodSorters
import org.junit.Assert;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class TestServerEnvKeystorePasswordPreserve extends AbstractIntegrationTest {
static File resourceDir = new File("build/resources/test/sample.servlet")
static File buildDir = new File(integTestDir, "/test-server-env-keystore-password-preserve")
static String buildFilename = "testServerEnvKeystorePasswordPreserve.gradle"

@BeforeClass
public static void setup() {
createDir(buildDir)
createTestProject(buildDir, resourceDir, buildFilename)
runTasks(buildDir, 'libertyCreate')
}

@Test
public void check_for_server_env() {
assert new File('build/testBuilds/test-server-env-keystore-password-preserve/build/wlp/usr/servers/LibertyProjectServer/server.env').exists() : 'server.env not found!'
}

/*
# envProps in build.gradle
env = ['TEST_PROP_2':'white', 'CONFIG_SERVER_ENV_PROPS':'TEST']

# default server.env
keystore_password=sfKRrA1ioLdtIFQC9bEfkua

# Final server.env
# Generated by liberty-gradle-plugin
keystore_password=sfKRrA1ioLdtIFQC9bEfkua
CONFIG_SERVER_ENV_PROPS=TEST
TEST_PROP_2=white
*/
@Test
public void check_server_env_contents() {
File serverEnv = new File("build/testBuilds/test-server-env-keystore-password-preserve/build/wlp/usr/servers/LibertyProjectServer/server.env")
FileInputStream input = new FileInputStream(serverEnv)

Map<String,String> serverEnvContents = new HashMap<String,String>();

BufferedReader bf = new BufferedReader(new FileReader(serverEnv))
String line = bf.readLine();
boolean commentFound = false
while(line != null) {
//ignore comment lines
if(!line.startsWith("#")) {
String[] keyValuePair = line.split("=");
String key = keyValuePair[0];
String value = keyValuePair[1];

serverEnvContents.put(key,value);
} else {
commentFound = true
Assert.assertTrue("File should have been generated by liberty-gradle-plugin", line.contains("liberty-gradle-plugin"));
}
line = bf.readLine();
}
Assert.assertTrue("Expected generated by liberty-gradle-plugin comment not found", commentFound);

// The contents of the default server.env can change over time.
// Only the keystore_password should be preserved at this time. Ensure that no additional lines are in the "merged" server.env file.
Assert.assertEquals("Number of env properties should be 3, but is "+serverEnvContents.size(), serverEnvContents.size(), 3)
Assert.assertTrue("keystore_password mapping found", serverEnvContents.containsKey("keystore_password"))
Assert.assertTrue("CONFIG_SERVER_ENV_PROPS=TEST", serverEnvContents.get("CONFIG_SERVER_ENV_PROPS").equals("TEST"))
Assert.assertTrue("TEST_PROP_2=white", serverEnvContents.get("TEST_PROP_2").equals("white"))

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
This test checks whether the application was successfully installed without the version number in the package
when deploy is called and stripVersion is set to true.
*/
group = 'liberty.gradle'
version = '1'

buildscript {
repositories {
mavenLocal()
mavenCentral()
maven {
name = 'Sonatype Nexus Snapshots'
url = 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
dependencies {
classpath "io.openliberty.tools:liberty-gradle-plugin:$lgpVersion"
}
}

apply plugin: 'war'
apply plugin: 'liberty'

sourceCompatibility = 1.7
targetCompatibility = 1.7

compileJava.options.encoding = 'UTF-8'

ext {
// Liberty server properties
wlpServerName = 'LibertyProjectServer'
serverDirectory = "${project.buildDir}/wlp/usr/servers/${wlpServerName}"
testServerHttpPort = 9080
testServerHttpsPort = 9443

// This is set in the ibm-web-ext.xml file
warContext = 'myLibertyApp'

}

liberty {
server{
serverXmlFile = file("src/main/liberty/config/server-apps-test.xml")
name = wlpServerName
deploy {
apps = [war]
copyLibsDirectory = file("${project.buildDir}/libs")
}
mergeServerEnv = true
env = ['TEST_PROP_2':'white', 'CONFIG_SERVER_ENV_PROPS':'TEST']
}
}

repositories {
mavenCentral()
}

dependencies {
testImplementation 'junit:junit:4.13.1'
providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version:'3.1.0'
implementation 'org.apache.commons:commons-text:1.1'
libertyRuntime group: runtimeGroup, name: kernelArtifactId, version: runtimeVersion
}

test {
println 'inside the test block'
reports.html.outputLocation = file("$buildDir/reports/unit")
reports.junitXml.outputLocation = file("$buildDir/test-results/unit")
exclude '**/it/**'
}

task integrationTest(type: Test) {
group 'Verification'
description 'Runs the integration tests.'
reports.html.outputLocation = file("$buildDir/reports/it")
reports.junitXml.outputLocation = file("$buildDir/test-results/it")
include '**/it/**'
exclude '**/unit/**'

systemProperties = ['liberty.test.port': testServerHttpPort, 'war.name': warContext]
}

task printMessageAboutRunningServer {
doLast {
println "The server is now running at http://localhost:${testServerHttpPort}/${warContext}"
println "To stop the server run 'gradle libertyStop'"
}
}

deploy.dependsOn 'war'
libertyStart.finalizedBy 'printMessageAboutRunningServer'