Skip to content

Commit 45a4001

Browse files
authored
fix: PJE enabler sample and password validation fixes (#1819)
* real PJE sample Signed-off-by: jandadav <janda.david@gmail.com> * PJE password validation fixes Signed-off-by: jandadav <janda.david@gmail.com> * checkstyle Signed-off-by: jandadav <janda.david@gmail.com> * Exclude sample from lite lib Signed-off-by: jandadav <janda.david@gmail.com> * skip enabler sonar Signed-off-by: jandadav <janda.david@gmail.com>
1 parent 25bbdbe commit 45a4001

File tree

11 files changed

+232
-12
lines changed

11 files changed

+232
-12
lines changed

gradle/lite.gradle

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,13 @@ task liteLibJarAll(type: Jar) {
4848
archiveName = getBaseNameLite() + ".jar"
4949
entryCompression = ZipEntryCompression.STORED
5050
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
51-
52-
from { rootProject.subprojects.collectMany {getLiteLibJarOutput(it.buildDir)}.collect() }
51+
from { rootProject.subprojects.collectMany {
52+
if (it.properties.get('projectPath').toString() != ':onboarding-enabler-java-sample-app-plain-java') {
53+
getLiteLibJarOutput(it.buildDir)
54+
} else {
55+
[]
56+
}
57+
}.collect() }
5358
}
5459

5560
build.dependsOn(liteLibJarAll)

gradle/sonar.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ project(":onboarding-enabler-nodejs") {
7272
}
7373
}
7474

75+
project(":onboarding-enabler-java-sample-app-plain-java") {
76+
sonarqube {
77+
skipProject = true
78+
}
79+
}
80+
7581
project(":onboarding-enabler-nodejs-sample-app") {
7682
sonarqube {
7783
skipProject = true
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
dependencies {
2+
compile (project(':onboarding-enabler-java'))
3+
compile ("javax.servlet:javax.servlet-api:4.0.1")
4+
}
5+
6+
jar {
7+
archiveName = "sample.jar"
8+
manifest {
9+
attributes "Main-Class": "org.zowe.apiml.sample.PlainJavaEnablerApp"
10+
}
11+
12+
from {
13+
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
14+
}
15+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
serviceId: plainjavaenablersample
2+
title: Plain java enabler sample
3+
description: Plain java enabler sample
4+
baseUrl: https://localhost:8080
5+
serviceIpAddress: 127.0.0.1
6+
preferIpAddress: false
7+
8+
homePageRelativeUrl: /greeting
9+
statusPageRelativeUrl: /status
10+
healthCheckRelativeUrl: /health
11+
12+
discoveryServiceUrls:
13+
- https://localhost:10011/eureka
14+
15+
routes:
16+
- gatewayUrl: api/v1
17+
serviceUrl: /
18+
19+
apiInfo:
20+
- apiId: org.zowe.pjesample
21+
version: 1.0.0
22+
gatewayUrl: api/v1
23+
swaggerUrl:
24+
doumentationUrl: https://localhost:8080/apidoc
25+
26+
27+
catalog:
28+
tile:
29+
id: cademoapps
30+
title: Sample API Mediation Layer Applications
31+
description: Applications which demonstrate how to make a service integrated to the API Mediation Layer ecosystem
32+
version: 1.0.0
33+
34+
ssl:
35+
verifySslCertificatesOfServices: true
36+
protocol: TLSv1.2
37+
keyAlias: localhost
38+
keyPassword: password
39+
keyStore: keystore/localhost/localhost.keystore.p12
40+
keyStorePassword: password
41+
keyStoreType: PKCS12
42+
trustStore: keystore/localhost/localhost.truststore.p12
43+
trustStorePassword: password
44+
trustStoreType: PKCS12
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Plain Java Enabler Sample
2+
✌( ͡° ͜ʖ ͡°)✌ "Superplain" edition
3+
4+
It's so _LIGHT_ that it doesn't have any _REST_ endpoints.
5+
6+
### Quick start
7+
8+
- run
9+
10+
`java -jar <jar location> <path to configuration>`
11+
12+
- run against local api-layer instance from api-layer repository root
13+
14+
`java -jar ./onboarding-enabler-java-sample-app-plain-java/build/libs/sample.jar ./onboarding-enabler-java-sample-app-plain-java/config/service-configuration.yml`
15+
16+
- run on mainframe (assuming artefacts in the same folder, with keyrings)
17+
18+
`java -Xquickstart -Dfile.encoding=UTF-8 -Djava.protocol.handler.pkgs=com.ibm.crypto.provider -jar sample.jar service-configuration.yml`
19+
20+
### Configuration
21+
Configuration sample can be found in the `config` folder. The config is for local api layer instance, running from repository root. Customize and use as you see fit.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* This program and the accompanying materials are made available under the terms of the
3+
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
4+
* https://www.eclipse.org/legal/epl-v20.html
5+
*
6+
* SPDX-License-Identifier: EPL-2.0
7+
*
8+
* Copyright Contributors to the Zowe Project.
9+
*/
10+
11+
package org.zowe.apiml.sample;
12+
13+
import org.zowe.apiml.eurekaservice.client.config.ApiMediationServiceConfig;
14+
import org.zowe.apiml.eurekaservice.client.impl.ApiMediationClientImpl;
15+
import org.zowe.apiml.eurekaservice.client.util.ApiMediationServiceConfigReader;
16+
import org.zowe.apiml.exception.ServiceDefinitionException;
17+
18+
import java.util.Objects;
19+
import java.util.logging.Logger;
20+
21+
public class PlainJavaEnablerApp {
22+
23+
private static Logger log = Logger.getLogger(PlainJavaEnablerApp.class.getName());
24+
25+
public static void main(String[] args) throws InterruptedException {
26+
if (args.length == 0 || Objects.isNull(args[0]) || args[0].isEmpty()) {
27+
throw new IllegalArgumentException("Please provide path to service configuration file as a first argument");
28+
}
29+
String configurationFile = args[0];
30+
try {
31+
ApiMediationServiceConfigReader reader = new ApiMediationServiceConfigReader();
32+
ApiMediationServiceConfig config = reader.loadConfiguration(configurationFile);
33+
ApiMediationClientImpl apiMediationClient = new ApiMediationClientImpl();
34+
apiMediationClient.register(config);
35+
} catch (ServiceDefinitionException sde) {
36+
log.severe("Service configuration failed. Check log for previous errors: " + sde.getMessage());
37+
sde.printStackTrace();
38+
throw new IllegalStateException("Configuration problem");
39+
}
40+
log.info("Configuration loaded, sleeping the main thread. Verify registration correctness in Discovery service");
41+
42+
Thread.currentThread().join();
43+
}
44+
}

onboarding-enabler-java-sample-app/build.gradle

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
buildscript {
22
repositories {
33
mavenCentral()
4+
gradlePluginPortal()
45
}
56
dependencies {
6-
classpath 'com.bmuschko:gradle-tomcat-plugin:2.5'
7+
classpath 'com.bmuschko:gradle-tomcat-plugin:2.7.0'
78
}
89
}
910

@@ -36,11 +37,10 @@ dependencies {
3637
testCompile libraries.mockito_core
3738
testCompile libraries.json_path
3839

39-
def tomcatVersion = '8.0.53'
40+
def tomcatVersion = '9.0.1'
4041
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
41-
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}",
42+
"org.apache.tomcat.embed:tomcat-embed-logging-juli:9.0.0.M6",
4243
"org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
43-
"org.apache.tomcat.embed:tomcat-servlet-api:${tomcatVersion}"
4444
}
4545

4646
tomcat {
@@ -53,4 +53,6 @@ tomcat {
5353
tomcatRun.truststoreFile = file("${project.rootDir}/keystore/localhost/localhost.truststore.p12")
5454
tomcatRun.keystorePass = "password"
5555
tomcatRun.truststorePass = "password"
56+
httpProtocol = 'org.apache.coyote.http11.Http11Nio2Protocol'
57+
ajpProtocol = 'org.apache.coyote.ajp.AjpNio2Protocol'
5658
}

onboarding-enabler-java/src/main/java/org/zowe/apiml/eurekaservice/client/util/EurekaInstanceConfigValidator.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class EurekaInstanceConfigValidator {
2828

2929
private static final String UNSET_VALUE_STRING = "{apiml.";
3030
private static final char[] UNSET_VALUE_CHAR_ARRAY = UNSET_VALUE_STRING.toCharArray();
31+
private static final String KEYRING_KEY = "JCERACFKS";
3132

3233
private final List<String> missingSslParameters = new ArrayList<>();
3334
private final List<String> missingRoutesParameters = new ArrayList<>();
@@ -94,9 +95,6 @@ private void validateSslParameters(Ssl ssl, List<String> missingSslParameters) {
9495
if (isInvalid(ssl.getTrustStoreType())) {
9596
addParameterToProblemsList("trustStoreType", missingSslParameters);
9697
}
97-
if (isInvalid(ssl.getKeyPassword())) {
98-
addParameterToProblemsList("keyPassword", missingSslParameters);
99-
}
10098
if (ssl.getEnabled() == null) {
10199
addParameterToProblemsList("enabled", missingSslParameters);
102100
}
@@ -105,13 +103,19 @@ private void validateSslParameters(Ssl ssl, List<String> missingSslParameters) {
105103
private void validateSsl(Ssl ssl) {
106104
validateSslParameters(ssl, missingSslParameters);
107105
if (isInvalid(ssl.getTrustStorePassword()) && (isInvalid(ssl.getTrustStoreType()) ||
108-
(!isInvalid(ssl.getTrustStoreType()) && !ssl.getTrustStoreType().equals("JCERACFKS")))) {
106+
(!isInvalid(ssl.getTrustStoreType()) && !ssl.getTrustStoreType().equals(KEYRING_KEY)))) {
109107
addParameterToProblemsList("trustStorePassword", missingSslParameters);
110108
}
111109
if (isInvalid(ssl.getKeyStorePassword()) && (isInvalid(ssl.getKeyStoreType()) ||
112-
(!isInvalid(ssl.getKeyStoreType()) && !ssl.getKeyStoreType().equals("JCERACFKS")))) {
110+
(!isInvalid(ssl.getKeyStoreType()) && !ssl.getKeyStoreType().equals(KEYRING_KEY)))) {
113111
addParameterToProblemsList("keyStorePassword", missingSslParameters);
114112
}
113+
if (isInvalid(ssl.getKeyPassword()) && (isInvalid(ssl.getKeyStoreType()) ||
114+
(!isInvalid(ssl.getKeyStoreType()) && !ssl.getKeyStoreType().equals(KEYRING_KEY)))) {
115+
addParameterToProblemsList("keyPassword", missingSslParameters);
116+
}
117+
118+
115119
if (!missingSslParameters.isEmpty()) {
116120
throw new MetadataValidationException(String.format("SSL parameters ** %s ** are missing or were not replaced by the system properties.", String.join(", ", missingSslParameters)));
117121
}

onboarding-enabler-java/src/test/java/org/zowe/apiml/eurekaservice/client/util/EurekaInstanceConfigValidatorTest.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import javax.servlet.ServletContext;
2626
import java.util.Collections;
27+
import java.util.function.Consumer;
2728

2829
import static org.junit.jupiter.api.Assertions.*;
2930

@@ -54,7 +55,7 @@ void givenServiceConfiguration_whenConfigurationIsValid_thenValidate() throws Se
5455
@CsvSource(value = {
5556
"bad-ssl-configuration.yml|SSL configuration was not provided. Try add apiml.service.ssl section.",
5657
"wrong-routes-service-configuration.yml|Routes parameters ** gatewayUrl, serviceUrl ** are missing or were not replaced by the system properties.",
57-
"missing-ssl-configuration.yml|SSL parameters ** protocol, trustStore, keyStore, keyAlias, keyStoreType, trustStoreType, keyPassword, enabled, trustStorePassword, keyStorePassword ** are missing or were not replaced by the system properties."
58+
"missing-ssl-configuration.yml|SSL parameters ** protocol, trustStore, keyStore, keyAlias, keyStoreType, trustStoreType, enabled, trustStorePassword, keyStorePassword, keyPassword ** are missing or were not replaced by the system properties."
5859
}, delimiter = '|')
5960
void givenConfigurationWithInvalidSsl_whenValidate_thenThrowException(String cfgFile, String expectedMsg) throws ServiceDefinitionException {
6061
ApiMediationServiceConfig testConfig = configReader.loadConfiguration(cfgFile);
@@ -71,6 +72,31 @@ void givenConfigurationWithHttpEurekaAndInvalidSsl_thenValidate() throws Service
7172
assertDoesNotThrow(() -> validator.validate(testConfig));
7273
}
7374

75+
@Test
76+
void emptyKeyringPasswordsAreSupported() throws ServiceDefinitionException {
77+
ApiMediationServiceConfig testConfig = configReader.loadConfiguration("service-configuration-keyring.yml");
78+
testConfig.setDiscoveryServiceUrls(Collections.singletonList("https://localhost:10011/eureka"));
79+
assertDoesNotThrow(() -> validator.validate(testConfig));
80+
}
81+
82+
@SuppressWarnings("squid:S5778") //Lambda formatting
83+
@Test
84+
void emptyPasswordsWithKeystoresAreValidatedAsErrors() {
85+
assertThrows(MetadataValidationException.class, () -> validator.validate(
86+
loadValidSslConfiguration(c -> c.getSsl().setKeyPassword(null))));
87+
assertThrows(MetadataValidationException.class, () -> validator.validate(
88+
loadValidSslConfiguration(c -> c.getSsl().setKeyStorePassword(null))));
89+
assertThrows(MetadataValidationException.class, () -> validator.validate(
90+
loadValidSslConfiguration(c -> c.getSsl().setTrustStorePassword(null))));
91+
}
92+
93+
private ApiMediationServiceConfig loadValidSslConfiguration(Consumer<ApiMediationServiceConfig> configModifier) throws ServiceDefinitionException {
94+
ApiMediationServiceConfig testConfig = configReader.loadConfiguration("service-configuration.yml");
95+
testConfig.setDiscoveryServiceUrls(Collections.singletonList("https://localhost:10011/eureka"));
96+
configModifier.accept(testConfig);
97+
return testConfig;
98+
}
99+
74100
@Test
75101
void givenSystemProperties_whenLoadFromFile_thenNoOverrideBySystemProp() throws Exception {
76102
System.setProperty("apiml.serviceId", "veronica");
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
serviceId: service
2+
title: HelloWorld Spring REST API
3+
description: POC for exposing a Spring REST API
4+
baseUrl: http://localhost:10021/hellospring
5+
serviceIpAddress: 127.0.0.1
6+
7+
homePageRelativeUrl: /
8+
statusPageRelativeUrl: /application/info
9+
healthCheckRelativeUrl: /application/health
10+
11+
discoveryServiceUrls:
12+
- http://eureka:password@localhost:10011/eureka
13+
- http://eureka:password@localhost:10011/eureka1
14+
15+
routes:
16+
- gatewayUrl: api/v1
17+
serviceUrl: /hellospring/api/v1
18+
- gatewayUrl: api/v1/api-doc
19+
serviceUrl: /hellospring/api-doc
20+
21+
apiInfo:
22+
- apiId: zowe.apiml.hellospring
23+
gatewayUrl: api/v1
24+
swaggerUrl: http://localhost:10021/hellospring/api-doc
25+
26+
catalog:
27+
tile:
28+
id: helloworld-spring
29+
title: HelloWorld Spring REST API
30+
description: Proof of Concept application to demonstrate exposing a REST API in the MFaaS ecosystem
31+
version: 1.0.0
32+
33+
ssl:
34+
enabled: true
35+
protocol: TLSv1.2
36+
keyAlias: localhost
37+
keyStore: safkeyring:////my_racf_id/my_key_ring
38+
keyStoreType: JCERACFKS
39+
trustStore: safkeyring:////my_racf_id/my_key_ring
40+
trustStoreType: JCERACFKS
41+
42+
customMetadata:
43+
key: value
44+
customService.key1: value1
45+
customService.key2: value2
46+
customService:
47+
key3: value3
48+
key4: value4
49+
evenmorelevels:
50+
key5:
51+
key6:
52+
key7: value7

0 commit comments

Comments
 (0)