From 33f488280d9cb97ddaa2ddc84eca4d6c54fcc05a Mon Sep 17 00:00:00 2001 From: achmelo <37397715+achmelo@users.noreply.github.com> Date: Thu, 16 Mar 2023 10:44:59 +0100 Subject: [PATCH] fix: refactor SSL configuration (#2832) * refactor TLS configuration Signed-off-by: achmelo * builder default bug workaround Signed-off-by: achmelo * default TLS protocol Signed-off-by: achmelo --------- Signed-off-by: achmelo --- .../src/main/resources/application.yml | 2 +- .../zowe/apiml/product/web/HttpConfig.java | 20 +++-- .../src/main/resources/application.yml | 2 +- ...HttpConfig.java => ConnectionsConfig.java} | 60 ++------------- .../config/RoutingConfig.java | 72 +++++++++++++++++ ...igTest.java => ConnectionsConfigTest.java} | 46 +++++------ .../org/zowe/apiml/security/HttpsConfig.java | 40 +++++----- .../org/zowe/apiml/security/HttpsFactory.java | 77 ++++++++----------- .../zowe/apiml/security/SecurityUtils.java | 17 ++-- .../zowe/apiml/security/HttpsFactoryTest.java | 16 ++-- .../apiml/security/SecurityTestUtils.java | 2 +- .../apiml/security/SecurityUtilsTest.java | 5 +- .../zowe/apiml/tomcat/TomcatHttpsTest.java | 21 +++-- .../apiml/tomcat/TomcatServerFactory.java | 20 ++--- .../src/main/resources/application.yml | 2 +- .../src/main/resources/application.yml | 2 +- .../src/main/resources/application.yml | 2 +- .../zaasclient/config/ConfigProperties.java | 21 +++-- 18 files changed, 222 insertions(+), 205 deletions(-) rename cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/{HttpConfig.java => ConnectionsConfig.java} (79%) create mode 100644 cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/RoutingConfig.java rename cloud-gateway-service/src/test/java/org/zowe/apiml/cloudgatewayservice/config/{HttpConfigTest.java => ConnectionsConfigTest.java} (61%) diff --git a/api-catalog-services/src/main/resources/application.yml b/api-catalog-services/src/main/resources/application.yml index 29f9591045..5912e48a00 100644 --- a/api-catalog-services/src/main/resources/application.yml +++ b/api-catalog-services/src/main/resources/application.yml @@ -67,7 +67,7 @@ apiml: security: ssl: sslEnabled: true - protocol: TLSv1.2 + protocol: TLS trustStore: ${server.ssl.truststore} trustStoreType: ${server.ssl.truststoreType} trustStorePassword: ${server.ssl.truststorePassword} diff --git a/apiml-common/src/main/java/org/zowe/apiml/product/web/HttpConfig.java b/apiml-common/src/main/java/org/zowe/apiml/product/web/HttpConfig.java index 5c4c9771d9..fa3fe0d010 100644 --- a/apiml-common/src/main/java/org/zowe/apiml/product/web/HttpConfig.java +++ b/apiml-common/src/main/java/org/zowe/apiml/product/web/HttpConfig.java @@ -48,8 +48,12 @@ public class HttpConfig { private static final char[] KEYRING_PASSWORD = "password".toCharArray(); - @Value("${server.ssl.protocol:TLSv1.2}") + @Value("${server.ssl.protocol:TLS}") private String protocol; + @Value("${apiml.httpclient.ssl.enabled-protocols:TLSv1.2,TLSv1.3}") + private String[] supportedProtocols; + @Value("${server.ssl.ciphers:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384}") + private String[] ciphers; @Value("${server.ssl.trustStore:#{null}}") private String trustStore; @@ -75,9 +79,6 @@ public class HttpConfig { @Value("${server.ssl.keyStoreType:PKCS12}") private String keyStoreType; - @Value("${server.ssl.ciphers:.*}") - private String[] ciphers; - @Value("${apiml.security.ssl.verifySslCertificatesOfServices:true}") private boolean verifySslCertificatesOfServices; @@ -108,9 +109,6 @@ public class HttpConfig { @Value("${apiml.httpclient.conn-pool.timeToLive:#{10000}}") private int timeToLive; - @Value("${server.attls.enabled:false}") - private boolean isAttlsEnabled; - private CloseableHttpClient secureHttpClient; private CloseableHttpClient secureHttpClientWithoutKeystore; private SSLContext secureSslContext; @@ -145,7 +143,7 @@ public void init() { try { Supplier httpsConfigSupplier = () -> HttpsConfig.builder() - .protocol(protocol) + .protocol(protocol).enabledProtocols(supportedProtocols).cipherSuite(ciphers) .trustStore(trustStore).trustStoreType(trustStoreType) .trustStorePassword(trustStorePassword).trustStoreRequired(trustStoreRequired) .verifySslCertificatesOfServices(verifySslCertificatesOfServices) @@ -156,7 +154,7 @@ public void init() { HttpsConfig httpsConfig = httpsConfigSupplier.get() .keyAlias(keyAlias).keyStore(keyStore).keyPassword(keyPassword) - .keyStorePassword(keyStorePassword).keyStoreType(keyStoreType).trustStore(trustStore) + .keyStorePassword(keyStorePassword).keyStoreType(keyStoreType) .build(); HttpsConfig httpsConfigWithoutKeystore = httpsConfigSupplier.get().build(); @@ -166,8 +164,8 @@ public void init() { HttpsFactory factory = new HttpsFactory(httpsConfig); ApimlPoolingHttpClientConnectionManager secureConnectionManager = getConnectionManager(factory); secureHttpClient = factory.createSecureHttpClient(secureConnectionManager); - secureSslContext = factory.createSslContext(); - secureHostnameVerifier = factory.createHostnameVerifier(); + secureSslContext = factory.getSslContext(); + secureHostnameVerifier = factory.getHostnameVerifier(); eurekaJerseyClientBuilder = factory.createEurekaJerseyClientBuilder(eurekaServerUrl, serviceId); optionalArgs.setEurekaJerseyClient(eurekaJerseyClient()); HttpsFactory factoryWithoutKeystore = new HttpsFactory(httpsConfigWithoutKeystore); diff --git a/caching-service/src/main/resources/application.yml b/caching-service/src/main/resources/application.yml index 1d3804355a..2d0f969eca 100644 --- a/caching-service/src/main/resources/application.yml +++ b/caching-service/src/main/resources/application.yml @@ -126,7 +126,7 @@ server: ssl: enabled: true clientAuth: want - protocol: TLSv1.2 + protocol: TLS enabled-protocols: TLSv1.2+TLSv1.3 ciphers: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384 keyStoreType: PKCS12 diff --git a/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/HttpConfig.java b/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/ConnectionsConfig.java similarity index 79% rename from cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/HttpConfig.java rename to cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/ConnectionsConfig.java index a7af7e00ac..3c88aff37c 100644 --- a/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/HttpConfig.java +++ b/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/ConnectionsConfig.java @@ -26,16 +26,12 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory; import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder; import org.springframework.cloud.client.circuitbreaker.Customizer; -import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.cloud.gateway.config.GlobalCorsProperties; import org.springframework.cloud.gateway.config.HttpClientCustomizer; -import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties; -import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping; import org.springframework.cloud.netflix.eureka.CloudEurekaClient; import org.springframework.cloud.netflix.eureka.MutableDiscoveryClientOptionalArgs; @@ -48,8 +44,6 @@ import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.pattern.PathPatternParser; -import org.zowe.apiml.cloudgatewayservice.service.ProxyRouteLocator; -import org.zowe.apiml.cloudgatewayservice.service.RouteLocator; import org.zowe.apiml.message.core.MessageService; import org.zowe.apiml.message.yaml.YamlMessageServiceInstance; import org.zowe.apiml.security.HttpsConfig; @@ -63,15 +57,11 @@ import javax.net.ssl.TrustManagerFactory; import java.security.KeyStore; import java.time.Duration; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; @Configuration @Slf4j -public class HttpConfig { +public class ConnectionsConfig { private static final char[] KEYRING_PASSWORD = "password".toCharArray(); @@ -121,16 +111,14 @@ public class HttpConfig { private int requestTimeout; @Value("${apiml.service.corsEnabled:false}") private boolean corsEnabled; - @Value("${apiml.service.ignoredHeadersWhenCorsEnabled:-}") - private String ignoredHeadersWhenCorsEnabled; private final ApplicationContext context; - public HttpConfig(ApplicationContext context) { + public ConnectionsConfig(ApplicationContext context) { this.context = context; } @PostConstruct - public void init() { + public void updateConfigParameters() { if (SecurityUtils.isKeyring(keyStorePath)) { keyStorePath = SecurityUtils.formatKeyringUrl(keyStorePath); if (keyStorePassword == null) keyStorePassword = KEYRING_PASSWORD; @@ -168,7 +156,9 @@ HttpClientCustomizer secureCustomizer() { } - + /** + * @return io.netty.handler.ssl.SslContext for http client. + */ SslContext sslContext() { try { KeyStore keyStore = SecurityUtils.loadKeyStore(keyStoreType, keyStorePath, keyStorePassword); @@ -208,21 +198,6 @@ public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientCon return cloudEurekaClient; } - - @Bean - @ConditionalOnProperty(name = "apiml.service.gateway.proxy.enabled", havingValue = "false") - public RouteLocator apimlDiscoveryRouteDefLocator( - ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties, List filters, ApplicationContext context, CorsUtils corsUtils) { - return new RouteLocator(discoveryClient, properties, filters, context, corsUtils); - } - - @Bean - @ConditionalOnProperty(name = "apiml.service.gateway.proxy.enabled", havingValue = "true") - public RouteLocator proxyRouteDefLocator( - ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties, List filters, ApplicationContext context, CorsUtils corsUtils) { - return new ProxyRouteLocator(discoveryClient, properties, filters, context, corsUtils); - } - @Bean public Customizer defaultCustomizer() { return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id) @@ -236,29 +211,6 @@ public WebClient webClient() { } - @Bean - public List filters() { - FilterDefinition circuitBreakerFilter = new FilterDefinition(); - circuitBreakerFilter.setName("CircuitBreaker"); - FilterDefinition retryFilter = new FilterDefinition(); - retryFilter.setName("Retry"); - - retryFilter.addArg("retries", "5"); - retryFilter.addArg("statuses", "SERVICE_UNAVAILABLE"); - List filters = new ArrayList<>(); - filters.add(circuitBreakerFilter); - filters.add(retryFilter); - for (String headerName : ignoredHeadersWhenCorsEnabled.split(",")) { - FilterDefinition removeHeaders = new FilterDefinition(); - removeHeaders.setName("RemoveRequestHeader"); - Map args = new HashMap<>(); - args.put("name", headerName); - removeHeaders.setArgs(args); - filters.add(removeHeaders); - } - return filters; - } - @Bean public CorsConfigurationSource corsConfigurationSource(RoutePredicateHandlerMapping handlerMapping, GlobalCorsProperties globalCorsProperties, CorsUtils corsUtils) { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser()); diff --git a/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/RoutingConfig.java b/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/RoutingConfig.java new file mode 100644 index 0000000000..7807952719 --- /dev/null +++ b/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/RoutingConfig.java @@ -0,0 +1,72 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +package org.zowe.apiml.cloudgatewayservice.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; +import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties; +import org.springframework.cloud.gateway.filter.FilterDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.zowe.apiml.cloudgatewayservice.service.ProxyRouteLocator; +import org.zowe.apiml.cloudgatewayservice.service.RouteLocator; +import org.zowe.apiml.util.CorsUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Configuration +public class RoutingConfig { + + @Value("${apiml.service.ignoredHeadersWhenCorsEnabled:-}") + private String ignoredHeadersWhenCorsEnabled; + + @Bean + @ConditionalOnProperty(name = "apiml.service.gateway.proxy.enabled", havingValue = "false") + public RouteLocator apimlDiscoveryRouteDefLocator( + ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties, List filters, ApplicationContext context, CorsUtils corsUtils) { + return new RouteLocator(discoveryClient, properties, filters, context, corsUtils); + } + + @Bean + @ConditionalOnProperty(name = "apiml.service.gateway.proxy.enabled", havingValue = "true") + public RouteLocator proxyRouteDefLocator( + ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties, List filters, ApplicationContext context, CorsUtils corsUtils) { + return new ProxyRouteLocator(discoveryClient, properties, filters, context, corsUtils); + } + + @Bean + public List filters() { + FilterDefinition circuitBreakerFilter = new FilterDefinition(); + circuitBreakerFilter.setName("CircuitBreaker"); + FilterDefinition retryFilter = new FilterDefinition(); + retryFilter.setName("Retry"); + + retryFilter.addArg("retries", "5"); + retryFilter.addArg("statuses", "SERVICE_UNAVAILABLE"); + List filters = new ArrayList<>(); + filters.add(circuitBreakerFilter); + filters.add(retryFilter); + for (String headerName : ignoredHeadersWhenCorsEnabled.split(",")) { + FilterDefinition removeHeaders = new FilterDefinition(); + removeHeaders.setName("RemoveRequestHeader"); + Map args = new HashMap<>(); + args.put("name", headerName); + removeHeaders.setArgs(args); + filters.add(removeHeaders); + } + return filters; + } +} diff --git a/cloud-gateway-service/src/test/java/org/zowe/apiml/cloudgatewayservice/config/HttpConfigTest.java b/cloud-gateway-service/src/test/java/org/zowe/apiml/cloudgatewayservice/config/ConnectionsConfigTest.java similarity index 61% rename from cloud-gateway-service/src/test/java/org/zowe/apiml/cloudgatewayservice/config/HttpConfigTest.java rename to cloud-gateway-service/src/test/java/org/zowe/apiml/cloudgatewayservice/config/ConnectionsConfigTest.java index 78e081294a..b98a06f948 100644 --- a/cloud-gateway-service/src/test/java/org/zowe/apiml/cloudgatewayservice/config/HttpConfigTest.java +++ b/cloud-gateway-service/src/test/java/org/zowe/apiml/cloudgatewayservice/config/ConnectionsConfigTest.java @@ -33,17 +33,19 @@ @SpringBootTest @ComponentScan(basePackages = "org.zowe.apiml.cloudgatewayservice") -class HttpConfigTest { +class ConnectionsConfigTest { @Autowired - private HttpConfig httpConfig; + private ConnectionsConfig connectionsConfig; + @Autowired + private RoutingConfig routingConfig; @Nested class WhenCreateEurekaJerseyClientBuilder { @Test void thenIsNotNull() { - Assertions.assertNotNull(httpConfig); - Assertions.assertNotNull(httpConfig.getEurekaJerseyClient()); + Assertions.assertNotNull(connectionsConfig); + Assertions.assertNotNull(connectionsConfig.getEurekaJerseyClient()); } } @@ -53,7 +55,7 @@ class WhenCreateRouteLocator { void thenIsNotNull() { ReactiveDiscoveryClient discoveryClient = mock(ReactiveDiscoveryClient.class); DiscoveryLocatorProperties properties = mock(DiscoveryLocatorProperties.class); - Assertions.assertNotNull(httpConfig.proxyRouteDefLocator(discoveryClient, properties, Collections.singletonList(new FilterDefinition("name=value")), null, null)); + Assertions.assertNotNull(routingConfig.proxyRouteDefLocator(discoveryClient, properties, Collections.singletonList(new FilterDefinition("name=value")), null, null)); } } @@ -73,7 +75,7 @@ class WhenInitializeEurekaClient { @Test void thenCreateIt() { - Assertions.assertNotNull(httpConfig.eurekaClient(manager, config, eurekaJerseyClient, healthCheckHandler)); + Assertions.assertNotNull(connectionsConfig.eurekaClient(manager, config, eurekaJerseyClient, healthCheckHandler)); } } @@ -82,30 +84,30 @@ class KeyringFormatAndPasswordUpdate { @Test void whenKeyringHasWrongFormatAndMissingPasswords_thenFixIt() { - HttpConfig httpConfig = new HttpConfig(null); - ReflectionTestUtils.setField(httpConfig, "keyStorePath", "safkeyring:///userId/ringId1"); - ReflectionTestUtils.setField(httpConfig, "trustStorePath", "safkeyring:////userId/ringId2"); + ConnectionsConfig connectionsConfig = new ConnectionsConfig(null); + ReflectionTestUtils.setField(connectionsConfig, "keyStorePath", "safkeyring:///userId/ringId1"); + ReflectionTestUtils.setField(connectionsConfig, "trustStorePath", "safkeyring:////userId/ringId2"); - httpConfig.init(); + connectionsConfig.updateConfigParameters(); - assertEquals("safkeyring://userId/ringId1", ReflectionTestUtils.getField(httpConfig, "keyStorePath")); - assertEquals("safkeyring://userId/ringId2", ReflectionTestUtils.getField(httpConfig, "trustStorePath")); - assertArrayEquals("password".toCharArray(), (char[]) ReflectionTestUtils.getField(httpConfig, "keyStorePassword")); - assertArrayEquals("password".toCharArray(), (char[]) ReflectionTestUtils.getField(httpConfig, "trustStorePassword")); + assertEquals("safkeyring://userId/ringId1", ReflectionTestUtils.getField(connectionsConfig, "keyStorePath")); + assertEquals("safkeyring://userId/ringId2", ReflectionTestUtils.getField(connectionsConfig, "trustStorePath")); + assertArrayEquals("password".toCharArray(), (char[]) ReflectionTestUtils.getField(connectionsConfig, "keyStorePassword")); + assertArrayEquals("password".toCharArray(), (char[]) ReflectionTestUtils.getField(connectionsConfig, "trustStorePassword")); } @Test void whenKeystore_thenDoNothing() { - HttpConfig httpConfig = new HttpConfig(null); - ReflectionTestUtils.setField(httpConfig, "keyStorePath", "/path1"); - ReflectionTestUtils.setField(httpConfig, "trustStorePath", "/path2"); + ConnectionsConfig connectionsConfig = new ConnectionsConfig(null); + ReflectionTestUtils.setField(connectionsConfig, "keyStorePath", "/path1"); + ReflectionTestUtils.setField(connectionsConfig, "trustStorePath", "/path2"); - httpConfig.init(); + connectionsConfig.updateConfigParameters(); - assertEquals("/path1", ReflectionTestUtils.getField(httpConfig, "keyStorePath")); - assertEquals("/path2", ReflectionTestUtils.getField(httpConfig, "trustStorePath")); - assertNull(ReflectionTestUtils.getField(httpConfig, "keyStorePassword")); - assertNull(ReflectionTestUtils.getField(httpConfig, "trustStorePassword")); + assertEquals("/path1", ReflectionTestUtils.getField(connectionsConfig, "keyStorePath")); + assertEquals("/path2", ReflectionTestUtils.getField(connectionsConfig, "trustStorePath")); + assertNull(ReflectionTestUtils.getField(connectionsConfig, "keyStorePassword")); + assertNull(ReflectionTestUtils.getField(connectionsConfig, "trustStorePassword")); } } diff --git a/common-service-core/src/main/java/org/zowe/apiml/security/HttpsConfig.java b/common-service-core/src/main/java/org/zowe/apiml/security/HttpsConfig.java index 98c6bc8654..bd5c2aa9d8 100644 --- a/common-service-core/src/main/java/org/zowe/apiml/security/HttpsConfig.java +++ b/common-service-core/src/main/java/org/zowe/apiml/security/HttpsConfig.java @@ -20,31 +20,35 @@ public class HttpsConfig { @Builder.Default - private String protocol = "TLSv1.2"; - private String trustStore; - private char[] trustStorePassword; + String protocol = "TLS"; @Builder.Default - private String trustStoreType = "PKCS12"; - private boolean trustStoreRequired; - private String keyAlias; - private String keyStore; - private char[] keyStorePassword; - private char[] keyPassword; + String[] enabledProtocols = "TLSv1.2,TLSv1.3".split(","); + String trustStore; + char[] trustStorePassword; @Builder.Default - private String keyStoreType = "PKCS12"; - private boolean clientAuth; + String trustStoreType = "PKCS12"; + boolean trustStoreRequired; + String keyAlias; + String keyStore; + char[] keyStorePassword; + char[] keyPassword; @Builder.Default - private boolean verifySslCertificatesOfServices = true; + String[] cipherSuite = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384".split(","); @Builder.Default - private boolean nonStrictVerifySslCertificatesOfServices = false; + String keyStoreType = "PKCS12"; + String clientAuth; @Builder.Default - private int maxConnectionsPerRoute = 10; + boolean verifySslCertificatesOfServices = true; @Builder.Default - private int maxTotalConnections = 100; + boolean nonStrictVerifySslCertificatesOfServices = false; @Builder.Default - private int idleConnTimeoutSeconds = 5; + int maxConnectionsPerRoute = 10; @Builder.Default - private int requestConnectionTimeout = 10_000; + int maxTotalConnections = 100; @Builder.Default - private int timeToLive = 10_000; + int idleConnTimeoutSeconds = 5; + @Builder.Default + int requestConnectionTimeout = 10_000; + @Builder.Default + int timeToLive = 10_000; } diff --git a/common-service-core/src/main/java/org/zowe/apiml/security/HttpsFactory.java b/common-service-core/src/main/java/org/zowe/apiml/security/HttpsFactory.java index a6df4a4fa5..6bcb989845 100644 --- a/common-service-core/src/main/java/org/zowe/apiml/security/HttpsFactory.java +++ b/common-service-core/src/main/java/org/zowe/apiml/security/HttpsFactory.java @@ -33,7 +33,6 @@ import javax.net.ssl.SSLContext; import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; import java.net.URL; import java.security.*; import java.security.cert.CertificateException; @@ -50,7 +49,6 @@ public class HttpsFactory { public HttpsFactory(HttpsConfig httpsConfig) { this.config = httpsConfig; - this.secureSslContext = null; this.apimlLog = ApimlLogger.of(HttpsFactory.class, YamlMessageServiceInstance.getInstance()); } @@ -61,7 +59,7 @@ public CloseableHttpClient createSecureHttpClient(HttpClientConnectionManager co .setConnectTimeout(config.getRequestConnectionTimeout()).build(); UserTokenHandler userTokenHandler = context -> context.getAttribute("my-token"); - return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setSSLHostnameVerifier(createHostnameVerifier()) + return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setSSLHostnameVerifier(getHostnameVerifier()) .setConnectionManager(connectionManager).disableCookieManagement().setUserTokenHandler(userTokenHandler) .setKeepAliveStrategy(ApimlKeepAliveStrategy.INSTANCE) .disableAuthCaching().build(); @@ -70,20 +68,13 @@ public CloseableHttpClient createSecureHttpClient(HttpClientConnectionManager co public ConnectionSocketFactory createSslSocketFactory() { if (config.isVerifySslCertificatesOfServices() || config.isNonStrictVerifySslCertificatesOfServices()) { - return createSecureSslSocketFactory(); + return getSSLConnectionSocketFactory(); } else { apimlLog.log("org.zowe.apiml.common.ignoringSsl"); return createIgnoringSslSocketFactory(); } } - /** - * Method is only for testing purpose. It is stored only in case of empty keystore (not if keystore is provided). - */ - KeyStore getUsedStore() { - return usedKeyStore; - } - private ConnectionSocketFactory createIgnoringSslSocketFactory() { return new SSLConnectionSocketFactory(createIgnoringSslContext(), new NoopHostnameVerifier()); } @@ -121,8 +112,10 @@ private void loadTrustMaterial(SSLContextBuilder sslContextBuilder) sslContextBuilder.loadTrustMaterial(trustStoreFile, config.getTrustStorePassword()); } else { - log.info("Loading trust store key ring: " + config.getTrustStore()); - sslContextBuilder.loadTrustMaterial(keyRingUrl(config.getTrustStore()), config.getTrustStorePassword()); + log.info("Original truststore keyring URL from configuration: " + config.getTrustStore()); + URL keyRingUrl = SecurityUtils.keyRingUrl(config.getTrustStore()); + log.info("Loading trusted certificates from keyring: " + keyRingUrl); + sslContextBuilder.loadTrustMaterial(keyRingUrl, config.getTrustStorePassword()); } } else { if (config.isTrustStoreRequired()) { @@ -136,10 +129,6 @@ private void loadTrustMaterial(SSLContextBuilder sslContextBuilder) } } - private URL keyRingUrl(String uri) throws MalformedURLException { - return SecurityUtils.keyRingUrl(uri, config.getTrustStore()); - } - private void loadKeyMaterial(SSLContextBuilder sslContextBuilder) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException, UnrecoverableKeyException { if (StringUtils.isNotEmpty(config.getKeyStore())) { @@ -151,7 +140,7 @@ private void loadKeyMaterial(SSLContextBuilder sslContextBuilder) throws NoSuchA loadKeyringMaterial(sslContextBuilder); } } else { - log.info("No key store is defined"); + log.info("No keystore is defined and empty will be used."); KeyStore emptyKeystore = KeyStore.getInstance(KeyStore.getDefaultType()); emptyKeystore.load(null, null); usedKeyStore = emptyKeystore; @@ -171,7 +160,7 @@ private void loadKeystoreMaterial(SSLContextBuilder sslContextBuilder) throws Un throw new HttpsConfigError("server.ssl.keyStorePassword configuration parameter is not defined", ErrorCode.KEYSTORE_PASSWORD_NOT_DEFINED, config); } - log.info("Loading key store file: " + config.getKeyStore()); + log.info("Loading keystore file: " + config.getKeyStore()); File keyStoreFile = new File(config.getKeyStore()); sslContextBuilder.loadKeyMaterial( keyStoreFile, config.getKeyStorePassword(), config.getKeyPassword(), @@ -185,30 +174,28 @@ private PrivateKeyStrategy getPrivateKeyStrategy() { private void loadKeyringMaterial(SSLContextBuilder sslContextBuilder) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException { - log.info("Loading trust key ring: " + config.getKeyStore()); - sslContextBuilder.loadKeyMaterial(keyRingUrl(config.getKeyStore()), config.getKeyStorePassword(), + log.info("Original keyring URL from configuration: " + config.getKeyStore()); + URL keyRingUrl = SecurityUtils.keyRingUrl(config.getKeyStore()); + log.info("Loading keyring from updated URL: " + keyRingUrl); + sslContextBuilder.loadKeyMaterial(keyRingUrl, config.getKeyStorePassword(), config.getKeyPassword(), getPrivateKeyStrategy()); } private synchronized SSLContext createSecureSslContext() { - if (secureSslContext == null) { - log.debug("Protocol: {}", config.getProtocol()); - SSLContextBuilder sslContextBuilder = SSLContexts.custom(); - try { - loadTrustMaterial(sslContextBuilder); - loadKeyMaterial(sslContextBuilder); - secureSslContext = sslContextBuilder.build(); - validateSslConfig(); - return secureSslContext; - } catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException - | UnrecoverableKeyException | KeyManagementException e) { - log.error("error", e); - apimlLog.log("org.zowe.apiml.common.sslContextInitializationError", e.getMessage()); - throw new HttpsConfigError("Error initializing SSL Context: " + e.getMessage(), e, - ErrorCode.HTTP_CLIENT_INITIALIZATION_FAILED, config); - } - } else { + log.debug("Protocol: {}", config.getProtocol()); + SSLContextBuilder sslContextBuilder = SSLContexts.custom(); + try { + loadTrustMaterial(sslContextBuilder); + loadKeyMaterial(sslContextBuilder); + secureSslContext = sslContextBuilder.build(); + validateSslConfig(); return secureSslContext; + } catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException + | UnrecoverableKeyException | KeyManagementException e) { + log.error("error", e); + apimlLog.log("org.zowe.apiml.common.sslContextInitializationError", e.getMessage()); + throw new HttpsConfigError("Error initializing SSL Context: " + e.getMessage(), e, + ErrorCode.HTTP_CLIENT_INITIALIZATION_FAILED, config); } } @@ -222,15 +209,15 @@ private void validateSslConfig() throws KeyStoreException, NoSuchAlgorithmExcept } } - private ConnectionSocketFactory createSecureSslSocketFactory() { - + private ConnectionSocketFactory getSSLConnectionSocketFactory() { return new SSLConnectionSocketFactory( createSecureSslContext(), - createHostnameVerifier() + config.getEnabledProtocols(), config.getCipherSuite(), + getHostnameVerifier() ); } - public SSLContext createSslContext() { + public SSLContext getSslContext() { if (config.isVerifySslCertificatesOfServices() || config.isNonStrictVerifySslCertificatesOfServices()) { return createSecureSslContext(); } else { @@ -258,7 +245,7 @@ public void setSystemSslProperties() { setSystemProperty("javax.net.ssl.trustStoreType", config.getTrustStoreType()); } - public HostnameVerifier createHostnameVerifier() { + public HostnameVerifier getHostnameVerifier() { if (config.isVerifySslCertificatesOfServices()) { return SSLConnectionSocketFactory.getDefaultHostnameVerifier(); } else { @@ -284,9 +271,9 @@ public EurekaJerseyClientBuilder createEurekaJerseyClientBuilder(String eurekaSe if (config.isVerifySslCertificatesOfServices() || config.isNonStrictVerifySslCertificatesOfServices()) { setSystemSslProperties(); } - builder.withCustomSSL(createSslContext()); + builder.withCustomSSL(getSslContext()); - builder.withHostnameVerifier(createHostnameVerifier()); + builder.withHostnameVerifier(getHostnameVerifier()); } return builder; } diff --git a/common-service-core/src/main/java/org/zowe/apiml/security/SecurityUtils.java b/common-service-core/src/main/java/org/zowe/apiml/security/SecurityUtils.java index aa0b0c5503..5038478168 100644 --- a/common-service-core/src/main/java/org/zowe/apiml/security/SecurityUtils.java +++ b/common-service-core/src/main/java/org/zowe/apiml/security/SecurityUtils.java @@ -73,7 +73,7 @@ public static Key loadKey(HttpsConfig config) { } return key; } catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException - | UnrecoverableKeyException e) { + | UnrecoverableKeyException e) { apimlLog.log("org.zowe.apiml.common.errorLoadingSecretKey", e.getMessage()); throw new HttpsConfigError(e.getMessage(), e, HttpsConfigError.ErrorCode.HTTP_CLIENT_INITIALIZATION_FAILED, config); @@ -182,7 +182,8 @@ public static Key findPrivateKeyByPublic(HttpsConfig config, byte[] publicKey) { } } return key; - } catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException | UnrecoverableKeyException e) { + } catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException | + UnrecoverableKeyException e) { apimlLog.log("org.zowe.apiml.common.errorLoadingSecretKey", e.getMessage()); throw new HttpsConfigError("Error loading secret key: " + e.getMessage(), e, HttpsConfigError.ErrorCode.HTTP_CLIENT_INITIALIZATION_FAILED, config); @@ -193,8 +194,9 @@ public static Key findPrivateKeyByPublic(HttpsConfig config, byte[] publicKey) { /** * Loads keystore or key ring, if keystore URL has proper format {@link #KEYRING_PATTERN}, from specified location - * @param type - type of store - * @param path - path or URL of store + * + * @param type - type of store + * @param path - path or URL of store * @param password - password to the store * @return the new {@link KeyStore} or key ring as {@link KeyStore} * @throws IOException @@ -232,14 +234,13 @@ public static KeyStore loadKeyStore(HttpsConfig config) throws KeyStoreException /** * Creates an {@link URL} to key ring location * - * @param uri - key ring location - * @param trustStore - truststore location + * @param uri - key ring location * @return the new {@link URL} with 2 slashes instead of 4 * @throws MalformedURLException throws in case of incorrect key ring format */ - public static URL keyRingUrl(String uri, String trustStore) throws MalformedURLException { + public static URL keyRingUrl(String uri) throws MalformedURLException { if (!isKeyring(uri)) { - throw new MalformedURLException("Incorrect key ring format: " + trustStore + throw new MalformedURLException("Incorrect key ring format: " + uri + ". Make sure you use format safkeyring://userId/keyRing"); } return new URL(formatKeyringUrl(uri)); diff --git a/common-service-core/src/test/java/org/zowe/apiml/security/HttpsFactoryTest.java b/common-service-core/src/test/java/org/zowe/apiml/security/HttpsFactoryTest.java index 47d09e83f3..0f95e9c4c0 100644 --- a/common-service-core/src/test/java/org/zowe/apiml/security/HttpsFactoryTest.java +++ b/common-service-core/src/test/java/org/zowe/apiml/security/HttpsFactoryTest.java @@ -63,7 +63,7 @@ void shouldCreateIgnoringSslSocketFactory() throws KeyStoreException { void shouldCreateSecureSslContextWithEmptyKeystoreWhenNoKeystoreIsProvided() throws KeyStoreException { HttpsConfig httpsConfig = HttpsConfig.builder().protocol("TLSv1.2").verifySslCertificatesOfServices(true).build(); HttpsFactory httpsFactory = new HttpsFactory(httpsConfig); - httpsFactory.createSslContext(); + httpsFactory.getSslContext(); assertFalse(httpsFactory.getUsedKeyStore().aliases().hasMoreElements()); } @@ -80,7 +80,7 @@ void shouldCreateSecureHttpClient() { void shouldCreateSecureSslContext() { HttpsConfig httpsConfig = httpsConfigBuilder.build(); HttpsFactory httpsFactory = new HttpsFactory(httpsConfig); - SSLContext sslContext = httpsFactory.createSslContext(); + SSLContext sslContext = httpsFactory.getSslContext(); assertNotNull(sslContext); assertEquals(SSLContext.class, sslContext.getClass()); } @@ -89,7 +89,7 @@ void shouldCreateSecureSslContext() { void shouldCreateIgnoringSslContext() { HttpsConfig httpsConfig = httpsConfigBuilder.verifySslCertificatesOfServices(false).build(); HttpsFactory httpsFactory = new HttpsFactory(httpsConfig); - SSLContext sslContext = httpsFactory.createSslContext(); + SSLContext sslContext = httpsFactory.getSslContext(); assertNotNull(sslContext); assertEquals(SSLContext.class, sslContext.getClass()); } @@ -98,21 +98,21 @@ void shouldCreateIgnoringSslContext() { void wrongKeyPasswordConfigurationShouldFail() { HttpsConfig httpsConfig = httpsConfigBuilder.keyPassword(INCORRECT_PARAMETER_VALUE.toCharArray()).build(); HttpsFactory httpsFactory = new HttpsFactory(httpsConfig); - assertThrows(HttpsConfigError.class, () -> httpsFactory.createSslContext()); + assertThrows(HttpsConfigError.class, () -> httpsFactory.getSslContext()); } @Test void specificIncorrectAliasShouldFail() { HttpsConfig httpsConfig = httpsConfigBuilder.trustStorePassword(INCORRECT_PARAMETER_VALUE.toCharArray()).build(); HttpsFactory httpsFactory = new HttpsFactory(httpsConfig); - assertThrows(HttpsConfigError.class, () -> httpsFactory.createSslContext()); + assertThrows(HttpsConfigError.class, () -> httpsFactory.getSslContext()); } @Test void incorrectProtocolShouldFail() { HttpsConfig httpsConfig = httpsConfigBuilder.verifySslCertificatesOfServices(false).protocol(INCORRECT_PARAMETER_VALUE).build(); HttpsFactory httpsFactory = new HttpsFactory(httpsConfig); - assertThrows(HttpsConfigError.class, () -> httpsFactory.createSslContext()); + assertThrows(HttpsConfigError.class, () -> httpsFactory.getSslContext()); } @Test @@ -134,7 +134,7 @@ void shouldSetSystemSslProperties() { void shouldCreateDefaultHostnameVerifier() { HttpsConfig httpsConfig = httpsConfigBuilder.build(); HttpsFactory httpsFactory = new HttpsFactory(httpsConfig); - HostnameVerifier hostnameVerifier = httpsFactory.createHostnameVerifier(); + HostnameVerifier hostnameVerifier = httpsFactory.getHostnameVerifier(); assertEquals(DefaultHostnameVerifier.class, hostnameVerifier.getClass()); } @@ -142,7 +142,7 @@ void shouldCreateDefaultHostnameVerifier() { void shouldCreateNoopHostnameVerifier() { HttpsConfig httpsConfig = httpsConfigBuilder.verifySslCertificatesOfServices(false).build(); HttpsFactory httpsFactory = new HttpsFactory(httpsConfig); - HostnameVerifier hostnameVerifier = httpsFactory.createHostnameVerifier(); + HostnameVerifier hostnameVerifier = httpsFactory.getHostnameVerifier(); assertEquals(NoopHostnameVerifier.class, hostnameVerifier.getClass()); } diff --git a/common-service-core/src/test/java/org/zowe/apiml/security/SecurityTestUtils.java b/common-service-core/src/test/java/org/zowe/apiml/security/SecurityTestUtils.java index b018a477ce..50c803b1db 100644 --- a/common-service-core/src/test/java/org/zowe/apiml/security/SecurityTestUtils.java +++ b/common-service-core/src/test/java/org/zowe/apiml/security/SecurityTestUtils.java @@ -28,7 +28,7 @@ public static HttpsConfig.HttpsConfigBuilder correctHttpsSettings() { } public static HttpsConfig.HttpsConfigBuilder correctHttpsKeyStoreSettings() { - return HttpsConfig.builder().protocol("TLSv1.2") + return HttpsConfig.builder() .keyStore(SecurityTestUtils.pathFromRepository("keystore/localhost/localhost.keystore.p12")) .keyStorePassword(STORE_PASSWORD).keyPassword(STORE_PASSWORD); } diff --git a/common-service-core/src/test/java/org/zowe/apiml/security/SecurityUtilsTest.java b/common-service-core/src/test/java/org/zowe/apiml/security/SecurityUtilsTest.java index 8101e9aa8d..2f208f111e 100644 --- a/common-service-core/src/test/java/org/zowe/apiml/security/SecurityUtilsTest.java +++ b/common-service-core/src/test/java/org/zowe/apiml/security/SecurityUtilsTest.java @@ -145,16 +145,17 @@ void loadCertificateChainBase64() throws CertificateException, NoSuchAlgorithmEx Set certificatesBase64 = SecurityUtils.loadCertificateChainBase64(httpsConfig); assertFalse(certificatesBase64.isEmpty()); } + @Nested class GivenKeyringUrl { @Test void thenThrowException() { - assertThrows(MalformedURLException.class, () -> SecurityUtils.keyRingUrl("safkeyring:////userId/keyRing", "safkeyring:////userId/keyRing")); + assertThrows(MalformedURLException.class, () -> SecurityUtils.keyRingUrl("safkeyring:////userId/keyRing")); } @Test void givenWrongFormat_thenThrowException() { - assertThrows(MalformedURLException.class, () -> SecurityUtils.keyRingUrl("safkeyring:/userId/keyRing", "safkeyring/userId/keyRing")); + assertThrows(MalformedURLException.class, () -> SecurityUtils.keyRingUrl("safkeyring:/userId/keyRing")); } } diff --git a/common-service-core/src/test/java/org/zowe/apiml/tomcat/TomcatHttpsTest.java b/common-service-core/src/test/java/org/zowe/apiml/tomcat/TomcatHttpsTest.java index 2d9555269b..1a53775e34 100644 --- a/common-service-core/src/test/java/org/zowe/apiml/tomcat/TomcatHttpsTest.java +++ b/common-service-core/src/test/java/org/zowe/apiml/tomcat/TomcatHttpsTest.java @@ -26,7 +26,6 @@ import org.zowe.apiml.security.*; import org.zowe.apiml.security.HttpsConfigError.ErrorCode; -import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import java.io.IOException; @@ -110,22 +109,22 @@ void wrongKeyAliasShouldFail() throws IOException, LifecycleException { @Test void correctConfigurationWithClientAuthenticationShouldWork() throws IOException, LifecycleException { - HttpsConfig httpsConfig = SecurityTestUtils.correctHttpsSettings().clientAuth(true).build(); + HttpsConfig httpsConfig = SecurityTestUtils.correctHttpsSettings().clientAuth("true").build(); startTomcatAndDoHttpsRequest(httpsConfig); } @Test - void wrongClientCertificateShouldFail() { - HttpsConfig serverConfig = SecurityTestUtils.correctHttpsSettings().clientAuth(true).build(); + void wrongClientCertificateShouldNotFailWhenClientAuthIsWant() throws Exception { + HttpsConfig serverConfig = SecurityTestUtils.correctHttpsSettings().clientAuth("want").build(); HttpsConfig clientConfig = SecurityTestUtils.correctHttpsSettings().keyStore(SecurityTestUtils.pathFromRepository("keystore/localhost/localhost2.keystore.p12")).build(); - assertThrows(SSLException.class, () -> - startTomcatAndDoHttpsRequest(serverConfig, clientConfig) - ); + + startTomcatAndDoHttpsRequest(serverConfig, clientConfig); + } @Test void wrongClientCertificateShouldNotFailWhenCertificateValidationIsDisabled() throws IOException, LifecycleException { - HttpsConfig serverConfig = SecurityTestUtils.correctHttpsSettings().clientAuth(true).verifySslCertificatesOfServices(false).build(); + HttpsConfig serverConfig = SecurityTestUtils.correctHttpsSettings().clientAuth("true").verifySslCertificatesOfServices(false).build(); HttpsConfig clientConfig = SecurityTestUtils.correctHttpsSettings().keyStore(SecurityTestUtils.pathFromRepository("keystore/localhost/localhost2.keystore.p12")).build(); startTomcatAndDoHttpsRequest(serverConfig, clientConfig); } @@ -142,10 +141,10 @@ private void startTomcatAndDoHttpsRequest(HttpsConfig serverConfig, HttpsConfig .create().register("http", PlainConnectionSocketFactory.getSocketFactory()); socketFactoryRegistryBuilder.register("https", clientHttpsFactory.createSslSocketFactory()); Registry socketFactoryRegistry = socketFactoryRegistryBuilder.build(); - - HttpClient client = clientHttpsFactory.createSecureHttpClient(new ApimlPoolingHttpClientConnectionManager(socketFactoryRegistry, clientConfig.getTimeToLive())); - + ApimlPoolingHttpClientConnectionManager connectionManager = new ApimlPoolingHttpClientConnectionManager(socketFactoryRegistry, clientConfig.getTimeToLive()); + HttpClient client = clientHttpsFactory.createSecureHttpClient(connectionManager); int port = TomcatServerFactory.getLocalPort(tomcat); + HttpGet get = new HttpGet(String.format("https://localhost:%d", port)); HttpResponse response = client.execute(get); diff --git a/common-service-core/src/test/java/org/zowe/apiml/tomcat/TomcatServerFactory.java b/common-service-core/src/test/java/org/zowe/apiml/tomcat/TomcatServerFactory.java index 6c9aabc6f1..55f8b012fb 100644 --- a/common-service-core/src/test/java/org/zowe/apiml/tomcat/TomcatServerFactory.java +++ b/common-service-core/src/test/java/org/zowe/apiml/tomcat/TomcatServerFactory.java @@ -76,20 +76,22 @@ private Connector createHttpsConnector(HttpsConfig httpsConfig) { httpsConnector.setPort(0); httpsConnector.setSecure(true); httpsConnector.setScheme("https"); - httpsConnector.setAttribute("clientAuth", - Boolean.toString(httpsConfig.isClientAuth() && httpsConfig.isVerifySslCertificatesOfServices())); - httpsConnector.setAttribute("keystoreFile", httpsConfig.getKeyStore()); - httpsConnector.setAttribute("keystorePass", + httpsConnector.setProperty("clientAuth", + Boolean.toString(Boolean.parseBoolean(httpsConfig.getClientAuth()) && httpsConfig.isVerifySslCertificatesOfServices())); + httpsConnector.setProperty("keystoreFile", httpsConfig.getKeyStore()); + httpsConnector.setProperty("ciphers",String.join(",",httpsConfig.getCipherSuite())); + httpsConnector.setProperty("enabled-protocols",String.join("+",httpsConfig.getEnabledProtocols())); + httpsConnector.setProperty("keystorePass", httpsConfig.getKeyStorePassword() == null ? null : String.valueOf(httpsConfig.getKeyStorePassword()) ); - if (httpsConfig.isClientAuth()) { - httpsConnector.setAttribute("truststoreFile", httpsConfig.getTrustStore()); - httpsConnector.setAttribute("truststorePass", + if (Boolean.parseBoolean(httpsConfig.getClientAuth()) || "want".equals(httpsConfig.getClientAuth())) { + httpsConnector.setProperty("truststoreFile", httpsConfig.getTrustStore()); + httpsConnector.setProperty("truststorePass", httpsConfig.getTrustStorePassword() == null ? null : String.valueOf(httpsConfig.getTrustStorePassword()) ); } - httpsConnector.setAttribute("sslProtocol", httpsConfig.getProtocol()); - httpsConnector.setAttribute("SSLEnabled", true); + httpsConnector.setProperty("sslProtocol", httpsConfig.getProtocol()); + httpsConnector.setProperty("SSLEnabled", "true"); return httpsConnector; } diff --git a/discovery-service/src/main/resources/application.yml b/discovery-service/src/main/resources/application.yml index e44691f7bd..49d0757358 100644 --- a/discovery-service/src/main/resources/application.yml +++ b/discovery-service/src/main/resources/application.yml @@ -109,7 +109,7 @@ server: ssl: enabled: true clientAuth: want - protocol: TLSv1.2 + protocol: TLS enabled-protocols: TLSv1.2+TLSv1.3 ciphers: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384 keyStoreType: PKCS12 diff --git a/gateway-service/src/main/resources/application.yml b/gateway-service/src/main/resources/application.yml index 3f98be8936..c01d6b9313 100644 --- a/gateway-service/src/main/resources/application.yml +++ b/gateway-service/src/main/resources/application.yml @@ -135,7 +135,7 @@ server: ssl: enabled: true clientAuth: want - protocol: TLSv1.2 + protocol: TLS enabled-protocols: TLSv1.2+TLSv1.3 ciphers: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384 keyStoreType: PKCS12 diff --git a/metrics-service/src/main/resources/application.yml b/metrics-service/src/main/resources/application.yml index fef7e2c219..2d8143e4a1 100644 --- a/metrics-service/src/main/resources/application.yml +++ b/metrics-service/src/main/resources/application.yml @@ -105,7 +105,7 @@ server: ssl: enabled: true clientAuth: want - protocol: TLSv1.2 + protocol: TLS enabled-protocols: TLSv1.2+TLSv1.3 ciphers: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384 keyStoreType: PKCS12 diff --git a/zaas-client/src/main/java/org/zowe/apiml/zaasclient/config/ConfigProperties.java b/zaas-client/src/main/java/org/zowe/apiml/zaasclient/config/ConfigProperties.java index 7c75ebc056..388588a6ae 100644 --- a/zaas-client/src/main/java/org/zowe/apiml/zaasclient/config/ConfigProperties.java +++ b/zaas-client/src/main/java/org/zowe/apiml/zaasclient/config/ConfigProperties.java @@ -34,10 +34,13 @@ public class ConfigProperties { private static final String GATEWAY_SERVICE_ID = "gateway"; + @Builder.Default private String tokenPrefix = "apimlAuthenticationToken"; + @Tolerate public ConfigProperties() { - // no args constructor + // lombok Builder.Default bug workaround + this.tokenPrefix = "apimlAuthenticationToken"; } public ConfigProperties withoutKeyStore() { @@ -50,29 +53,25 @@ public ConfigProperties withoutKeyStore() { .trustStorePassword(trustStorePassword) .httpOnly(httpOnly) .nonStrictVerifySslCertificatesOfServices(nonStrictVerifySslCertificatesOfServices) + .tokenPrefix(tokenPrefix) .build(); } public void setApimlBaseUrl(String baseUrl) { if (baseUrl == null) { // default path apimlBaseUrl = "/gateway/api/v1/auth"; - } - else if (baseUrl.contains("/") && baseUrl.contains(GATEWAY_SERVICE_ID)) { + } else if (baseUrl.contains("/") && baseUrl.contains(GATEWAY_SERVICE_ID)) { String[] baseUrlParts = baseUrl.split("/"); if (Objects.equals(baseUrlParts[2], GATEWAY_SERVICE_ID)) { apimlBaseUrl = "/gateway/" + baseUrlParts[0] + "/" + baseUrlParts[1] + "/auth"; - } - else if (Objects.equals(baseUrlParts[3], GATEWAY_SERVICE_ID)) { + } else if (Objects.equals(baseUrlParts[3], GATEWAY_SERVICE_ID)) { apimlBaseUrl = "/gateway/" + baseUrlParts[1] + "/" + baseUrlParts[2] + "/auth"; - } - else if (!baseUrl.startsWith("/")) { // starts with gateway/.. + } else if (!baseUrl.startsWith("/")) { // starts with gateway/.. apimlBaseUrl = "/" + baseUrl; - } - else { + } else { apimlBaseUrl = baseUrl; } - } - else { + } else { apimlBaseUrl = baseUrl; } }