diff --git a/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/ApiDocRetrievalServiceLocal.java b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/ApiDocRetrievalServiceLocal.java index d7e4f7e312..c04753dcca 100644 --- a/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/ApiDocRetrievalServiceLocal.java +++ b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/ApiDocRetrievalServiceLocal.java @@ -33,6 +33,7 @@ import org.zowe.apiml.apicatalog.model.ApiDocInfo; import org.zowe.apiml.config.ApiInfo; import org.zowe.apiml.product.gateway.GatewayClient; +import org.zowe.apiml.util.UrlUtils; import reactor.core.publisher.Mono; import java.util.*; @@ -78,7 +79,7 @@ springDocProviders, new SpringDocCustomizers(Optional.of(openApiCustomizers), Op @Override protected String getServerUrl(ServerHttpRequest serverHttpRequest, String apiDocsUrl) { var gw = gatewayClient.getGatewayConfigProperties(); - return String.format("%s://%s%s", gw.getScheme(), gw.getHostname(), apiDocsUrl); + return UrlUtils.getUrl(gw.getScheme(), gw.getHostname()) + apiDocsUrl; } }; diff --git a/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3Service.java b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3Service.java index 5471cb6711..f4b145691c 100644 --- a/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3Service.java +++ b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3Service.java @@ -41,6 +41,7 @@ import org.zowe.apiml.product.gateway.GatewayClient; import org.zowe.apiml.product.instance.ServiceAddress; import org.zowe.apiml.product.routing.RoutedService; +import org.zowe.apiml.util.UrlUtils; import java.net.URI; import java.util.Collections; @@ -106,7 +107,7 @@ private void updateServer(OpenAPI openAPI) { if (openAPI.getServers() != null) { openAPI.getServers() .forEach(server -> server.setUrl( - String.format("%s://%s/%s", scheme, getHostname(), server.getUrl()))); + UrlUtils.getUrl(scheme, UrlUtils.formatHostnameForUrl(getHostname())) + "/" + server.getUrl())); } } diff --git a/api-catalog-services/src/test/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3ServiceTest.java b/api-catalog-services/src/test/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3ServiceTest.java index de5b4b66e5..37f5d69e2e 100644 --- a/api-catalog-services/src/test/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3ServiceTest.java +++ b/api-catalog-services/src/test/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3ServiceTest.java @@ -250,7 +250,10 @@ private void verifyOpenApi3(OpenAPI openAPI) { @Test void givenInputFile_thenParseItCorrectly() throws IOException { - ServiceAddress gatewayConfigProperties = ServiceAddress.builder().scheme("https").hostname("localhost").build(); + ServiceAddress gatewayConfigProperties = ServiceAddress.builder() + .scheme("https") + .hostname("localhost:10010") + .build(); gatewayClient.setGatewayConfigProperties(gatewayConfigProperties); AtomicReference openApiHolder = new AtomicReference<>(); @@ -261,6 +264,9 @@ protected void updateExternalDoc(OpenAPI openAPI, ApiDocInfo apiDocInfo) { openApiHolder.set(openAPI); } }; + // Set the scheme field for the new ApiDocV3Service instance + ReflectionTestUtils.setField(apiDocV3Service, "scheme", "https"); + String transformed = apiDocV3Service.transformApiDoc("serviceId", ApiDocInfo.builder() .apiInfo(mock(ApiInfo.class)) .apiDocContent(IOUtils.toString(new ClassPathResource("swagger/openapi3.json").getInputStream(), StandardCharsets.UTF_8)) diff --git a/common-service-core/src/main/java/org/zowe/apiml/util/UrlUtils.java b/common-service-core/src/main/java/org/zowe/apiml/util/UrlUtils.java index 307b1aa7db..222e12be3b 100644 --- a/common-service-core/src/main/java/org/zowe/apiml/util/UrlUtils.java +++ b/common-service-core/src/main/java/org/zowe/apiml/util/UrlUtils.java @@ -112,4 +112,128 @@ public boolean isValidUrl(String urlString) { return false; } } + + /** + * Determines if a given string is an IPv6 address. + * + * @param address The string to check + * @return true if the address is an IPv6 address, false otherwise + */ + private boolean isIPv6Address(String address) { + try { + return InetAddress.getByName(address) instanceof Inet6Address; + } catch (UnknownHostException e) { + return false; + } + } + + /** + * Validates if a string represents a valid port number. + * + * @param port The string to validate as a port number + * @return true if the string represents a valid port, false otherwise + */ + private boolean isValidPort(String port) { + + if (port == null || port.isEmpty()) { + return false; + } + + try { + int portNum = Integer.parseInt(port); + return portNum >= 0 && portNum <= 65535; + } catch (NumberFormatException e) { + return false; + } + } + + /** + * Formats a hostname properly, ensuring IPv6 addresses are enclosed in square brackets. + * If the input is already a properly formatted IPv6 address (with brackets), it remains unchanged. + * Handles both IPv6 addresses and hostname:port combinations. + * + * @param hostname The hostname or IP address to format + * @return Properly formatted hostname, with IPv6 addresses enclosed in square brackets + */ + public String formatHostnameForUrl(String hostname) { + if (hostname == null || hostname.isEmpty()) { + return hostname; + } + + // If already properly formatted with brackets, return as is + if (hostname.startsWith("[") && hostname.contains("]")) { + return hostname; + } + + // Check for hostname:port format by looking at the last colon + // We check this BEFORE checking if the entire string is IPv6 because: + // 1. "2001:db8::1:8080" could be ambiguous - is 8080 part of IPv6 or a port? + // 2. If the last segment after colon is a valid port number, we should treat it as such + int lastColonIndex = hostname.lastIndexOf(':'); + if (lastColonIndex > -1) { + String possibleHost = hostname.substring(0, lastColonIndex); + String possiblePort = hostname.substring(lastColonIndex + 1); + + // Check if what follows the last colon is a valid port number + if (isValidPort(possiblePort)) { + // If we have a valid port, check if the host part is IPv6 + if (isIPv6Address(possibleHost)) { + return "[" + possibleHost + "]:" + possiblePort; + } + // If the full string is NOT IPv6, return as-is (hostname:port or IPv4:port) + if (!isIPv6Address(hostname)) { + return hostname; + } + // Edge case: If full hostname IS IPv6 but possibleHost is not, + // fall through to check if it's a plain IPv6 address without port + } + } + + // No valid port found, check if it's a plain IPv6 address + if (isIPv6Address(hostname)) { + return "[" + hostname + "]"; + } + + return hostname; + } + + /** + * Creates a proper URL string with scheme, hostname, and port, + * handling IPv6 addresses correctly. + * + * @param scheme The URL scheme (http, https, etc.) + * @param hostname The hostname or IP address + * @param port The port number + * @return A properly formatted URL string with IPv6 address handling + */ + public String getUrl(String scheme, String hostname, int port) { + String formattedHostname = formatHostnameForUrl(hostname); + return String.format("%s://%s:%d", scheme, formattedHostname, port); + } + + /** + * Creates a proper URL string with scheme and host (which may include port), + * handling IPv6 addresses correctly. + * + * @param scheme The URL scheme (http, https, etc.) + * @param hostWithPort The hostname or IP address, possibly including a port + * @return A properly formatted URL string with IPv6 address handling + */ + public String getUrl(String scheme, String hostWithPort) { + if (scheme == null || scheme.isEmpty()) { + throw new IllegalArgumentException("Scheme cannot be null or empty"); + } + + if (hostWithPort == null || hostWithPort.isEmpty()) { + throw new IllegalArgumentException("Host cannot be null or empty"); + } + + // Remove any existing scheme if present + String cleanHostWithPort = hostWithPort.replaceFirst("^[a-zA-Z][a-zA-Z0-9+.-]*://", ""); + + // Format the hostname part properly + String formattedHost = formatHostnameForUrl(cleanHostWithPort); + + return String.format("%s://%s", scheme, formattedHost); + } } diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/caching/CachingServiceClientRest.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/caching/CachingServiceClientRest.java index 34d425939a..d53b0158f5 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/caching/CachingServiceClientRest.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/caching/CachingServiceClientRest.java @@ -19,6 +19,7 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.client.WebClient; import org.zowe.apiml.product.gateway.GatewayClient; +import org.zowe.apiml.util.UrlUtils; import reactor.core.publisher.Mono; import static reactor.core.publisher.Mono.empty; @@ -55,7 +56,10 @@ public CachingServiceClientRest( void updateUrl() { // Lazy initialization of GatewayClient's ServerAddress may bring invalid URL during initialization - this.cachingBalancerUrl = String.format("%s://%s/%s", gatewayClient.getGatewayConfigProperties().getScheme(), gatewayClient.getGatewayConfigProperties().getHostname(), CACHING_API_PATH); + this.cachingBalancerUrl = UrlUtils.getUrl( + gatewayClient.getGatewayConfigProperties().getScheme(), + gatewayClient.getGatewayConfigProperties().getHostname() + ) + "/" + CACHING_API_PATH; } public Mono create(ApiKeyValue keyValue) { diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/RegistryConfig.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/RegistryConfig.java index 834b163994..da45139588 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/RegistryConfig.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/RegistryConfig.java @@ -11,6 +11,7 @@ package org.zowe.apiml.gateway.config; import com.netflix.discovery.EurekaClient; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -21,7 +22,9 @@ import java.net.URI; import java.net.URISyntaxException; +import org.zowe.apiml.util.UrlUtils; +@Slf4j @Configuration public class RegistryConfig { @@ -42,15 +45,29 @@ ServiceAddress gatewayServiceAddress( ) throws URISyntaxException { if (externalUrl != null) { URI uri = new URI(externalUrl); - return ServiceAddress.builder() - .scheme(clientAttlsEnabled ? "http" : uri.getScheme()) - .hostname(uri.getHost() + ":" + uri.getPort()) - .build(); + String host = uri.getHost(); + + // Validate that the external URL has a valid host component + if (host == null || host.trim().isEmpty()) { + log.warn("Invalid external URL '{}' has no valid host component. Falling back to default configuration (hostname:port).", externalUrl); + // Fall through to use the default hostname and port configuration below + } else { + // Handle IPv6 address format using UrlUtils + host = UrlUtils.formatHostnameForUrl(host); + + return ServiceAddress.builder() + .scheme(clientAttlsEnabled ? "http" : uri.getScheme()) + .hostname(host + ":" + uri.getPort()) + .build(); + } } + // Handle IPv6 address format using UrlUtils + String formattedHostname = UrlUtils.formatHostnameForUrl(hostname); + return ServiceAddress.builder() .scheme(determineScheme(serverAttlsEnabled, clientAttlsEnabled, sslEnabled)) - .hostname(hostname + ":" + port) + .hostname(formattedHostname + ":" + port) .build(); } diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/filters/ZaasSchemeTransformRest.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/filters/ZaasSchemeTransformRest.java index c75e4256d7..bd7e9910ff 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/filters/ZaasSchemeTransformRest.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/filters/ZaasSchemeTransformRest.java @@ -28,6 +28,7 @@ import org.zowe.apiml.security.common.error.ServiceNotAccessibleException; import org.zowe.apiml.ticket.TicketRequest; import org.zowe.apiml.ticket.TicketResponse; +import org.zowe.apiml.util.UrlUtils; import org.zowe.apiml.zaas.ZaasTokenResponse; import reactor.core.publisher.Mono; @@ -129,7 +130,8 @@ private WebClient.RequestHeadersSpec createRequest(RequestCredentials request } private String getUrl(String pattern, ServiceInstance instance) { - return String.format(pattern, instance.getScheme(), instance.getHost(), instance.getPort(), instance.getServiceId().toLowerCase()); + String host = UrlUtils.formatHostnameForUrl(instance.getHost()); + return String.format(pattern, instance.getScheme(), host, instance.getPort(), instance.getServiceId().toLowerCase()); } @Override diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/service/GatewayIndexService.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/service/GatewayIndexService.java index 79ff31fa5d..411ada0c31 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/service/GatewayIndexService.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/service/GatewayIndexService.java @@ -29,6 +29,7 @@ import org.zowe.apiml.message.log.ApimlLogger; import org.zowe.apiml.message.yaml.YamlMessageServiceInstance; import org.zowe.apiml.services.ServiceInfo; +import org.zowe.apiml.util.UrlUtils; import reactor.core.publisher.Mono; import java.util.*; @@ -67,7 +68,7 @@ public GatewayIndexService( } private WebClient buildWebClient(ServiceInstance registration) { - final String baseUrl = String.format("%s://%s:%d", registration.getScheme(), registration.getHost(), registration.getPort()); + final String baseUrl = UrlUtils.getUrl(registration.getScheme(), registration.getHost(), registration.getPort()); return webClient.mutate() .baseUrl(baseUrl) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/service/routing/RouteDefinitionProducer.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/service/routing/RouteDefinitionProducer.java index 3e8e6992aa..20c63a3db2 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/service/routing/RouteDefinitionProducer.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/service/routing/RouteDefinitionProducer.java @@ -12,16 +12,18 @@ import lombok.RequiredArgsConstructor; import lombok.experimental.Delegate; +import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.SimpleEvaluationContext; +import java.net.URI; +import java.net.URISyntaxException; +import org.zowe.apiml.util.UrlUtils; import org.springframework.util.StringUtils; import org.zowe.apiml.product.routing.RoutedService; - -import java.net.URI; import java.util.LinkedHashMap; import java.util.Map; @@ -33,6 +35,7 @@ * * The producers define an order ({@link #getOrder()}). It allows to create multiple rules with a prioritization. */ +@Slf4j public abstract class RouteDefinitionProducer { protected final SimpleEvaluationContext evalCtxt = SimpleEvaluationContext.forReadOnlyDataBinding().withInstanceMethods().build(); @@ -58,9 +61,52 @@ protected String getHostname(ServiceInstance serviceInstance) { Map metadata = serviceInstance.getMetadata(); if (metadata != null) { output = metadata.get(SERVICE_EXTERNAL_URL); + + // If we have an external URL and it's not a load balancer URL, format it + if (output != null && !output.startsWith("lb://")) { + try { + URI uri = new URI(output); + String formattedHost = UrlUtils.formatHostnameForUrl(uri.getHost()); + if (formattedHost != null) { + URI newUri = new URI( + uri.getScheme(), + uri.getUserInfo(), + formattedHost, + uri.getPort(), + uri.getPath(), + uri.getQuery(), + uri.getFragment() + ); + output = newUri.toString(); + } + } catch (URISyntaxException e) { + log.error("Error while formatting URI: {}", output, e); + } + } } if (output == null) { - output = evalHostname(serviceInstance); + String evalHost = evalHostname(serviceInstance); + // Return load balancer URL as is, format others + if (!evalHost.startsWith("lb://")) { + try { + URI uri = new URI(evalHost); + String formattedHost = UrlUtils.formatHostnameForUrl(uri.getHost()); + if (formattedHost != null) { + evalHost = new URI( + uri.getScheme(), + uri.getUserInfo(), + formattedHost, + uri.getPort(), + uri.getPath(), + uri.getQuery(), + uri.getFragment() + ).toString(); + } + } catch (URISyntaxException e) { + log.error("Error while formatting URI: {}", evalHost, e); + } + } + output = evalHost; } return output; } @@ -83,7 +129,9 @@ protected RouteDefinition buildRouteDefinition(ServiceInstance serviceInstance, RouteDefinition routeDefinition = new RouteDefinition(); routeDefinition.setId(serviceInstance.getInstanceId() + ":" + routeId); routeDefinition.setOrder(getOrder()); - routeDefinition.setUri(URI.create(getHostname(serviceInstance))); + String hostname = getHostname(serviceInstance); + + routeDefinition.setUri(URI.create(hostname)); // add instance metadata routeDefinition.setMetadata(new LinkedHashMap<>(serviceInstance.getMetadata())); diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/services/ServicesInfoService.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/services/ServicesInfoService.java index 85c9adfc6a..41be4d9257 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/services/ServicesInfoService.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/services/ServicesInfoService.java @@ -28,6 +28,7 @@ import org.zowe.apiml.product.routing.ServiceType; import org.zowe.apiml.product.routing.transform.TransformService; import org.zowe.apiml.product.routing.transform.URLTransformationException; +import org.zowe.apiml.util.UrlUtils; import org.zowe.apiml.services.ServiceInfo; import org.zowe.apiml.services.ServiceInfoUtils; @@ -92,8 +93,8 @@ public ServiceInfo getServiceInfo(String serviceId) { private String getBaseUrl(ApiInfo apiInfo, InstanceInfo instanceInfo) { ServiceAddress gatewayAddress = gatewayClient.getGatewayConfigProperties(); - return String.format("%s://%s%s", - gatewayAddress.getScheme(), gatewayAddress.getHostname(), getBasePath(apiInfo, instanceInfo)); + return UrlUtils.getUrl(gatewayAddress.getScheme(), gatewayAddress.getHostname()) + + getBasePath(apiInfo, instanceInfo); } static List getPrimaryInstances(Application application) { diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/acceptance/config/DiscoveryClientTestConfig.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/acceptance/config/DiscoveryClientTestConfig.java index 1228c536db..667cb0bc61 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/acceptance/config/DiscoveryClientTestConfig.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/acceptance/config/DiscoveryClientTestConfig.java @@ -21,8 +21,6 @@ import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; import org.springframework.cloud.context.config.annotation.RefreshScope; -import org.springframework.cloud.netflix.eureka.RestClientTimeoutProperties; -import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier; import org.springframework.cloud.netflix.eureka.http.RestClientDiscoveryClientOptionalArgs; import org.springframework.cloud.netflix.eureka.http.RestClientTransportClientFactories; import org.springframework.cloud.util.ProxyUtils; @@ -94,9 +92,10 @@ ApimlDiscoveryClientStub eurekaClient(ApplicationInfoManager manager, appManager = manager; } - - var factorySupplier = new DefaultEurekaClientHttpRequestFactorySupplier(new RestClientTimeoutProperties()); - var args1 = new RestClientDiscoveryClientOptionalArgs(factorySupplier, RestClient::builder); + // Use RestClientDiscoveryClientOptionalArgs with default RestClient builder + // The DefaultEurekaClientHttpRequestFactorySupplier constructors are deprecated, + // so we pass null for the supplier and let Spring Cloud use its defaults + var args1 = new RestClientDiscoveryClientOptionalArgs(null, RestClient::builder); var factories = new RestClientTransportClientFactories(args1); final var discoveryClient = new ApimlDiscoveryClientStub(appManager, config, this.context, applicationRegistry, factories, args1); discoveryClient.registerHealthCheck(healthCheckHandler); diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/caching/CachingServiceClientRestTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/caching/CachingServiceClientRestTest.java index 376dfe9286..ec31739c19 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/caching/CachingServiceClientRestTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/caching/CachingServiceClientRestTest.java @@ -54,7 +54,10 @@ class CachingServiceClientRestTest { @BeforeEach void setUp() { webClient = spy(WebClient.builder().exchangeFunction(exchangeFunction).build()); - client = new CachingServiceClientRest(webClient, new GatewayClient(ServiceAddress.builder().build())); + client = new CachingServiceClientRest(webClient, new GatewayClient(ServiceAddress.builder() + .scheme("https") + .hostname("localhost:10011") + .build())); lenient().when(clientResponse.releaseBody()).thenReturn(empty()); } diff --git a/security-service-client-spring/src/main/java/org/zowe/apiml/security/client/service/GatewaySecurityService.java b/security-service-client-spring/src/main/java/org/zowe/apiml/security/client/service/GatewaySecurityService.java index 9709a06cd7..24d8766d2d 100644 --- a/security-service-client-spring/src/main/java/org/zowe/apiml/security/client/service/GatewaySecurityService.java +++ b/security-service-client-spring/src/main/java/org/zowe/apiml/security/client/service/GatewaySecurityService.java @@ -29,6 +29,7 @@ import org.zowe.apiml.product.gateway.GatewayClient; import org.zowe.apiml.product.instance.ServiceAddress; import org.zowe.apiml.security.client.handler.RestResponseHandler; +import org.zowe.apiml.util.UrlUtils; import org.zowe.apiml.security.common.config.AuthConfigurationProperties; import org.zowe.apiml.security.common.error.ErrorType; import org.zowe.apiml.security.common.login.LoginRequest; @@ -58,8 +59,8 @@ public class GatewaySecurityService implements GatewaySecurity { @Override public Optional login(String username, char[] password, char[] newPassword) { ServiceAddress gatewayConfigProperties = gatewayClient.getGatewayConfigProperties(); - String uri = String.format("%s://%s%s", gatewayConfigProperties.getScheme(), - gatewayConfigProperties.getHostname(), authConfigurationProperties.getGatewayLoginEndpoint()); + String uri = UrlUtils.getUrl(gatewayConfigProperties.getScheme(), gatewayConfigProperties.getHostname()) + + authConfigurationProperties.getGatewayLoginEndpoint(); LoginRequest loginRequest = new LoginRequest(username, password); if (!ArrayUtils.isEmpty(newPassword)) { @@ -95,8 +96,8 @@ public Optional login(String username, char[] password, char[] newPasswo @Override public QueryResponse query(String token) { ServiceAddress gatewayConfigProperties = gatewayClient.getGatewayConfigProperties(); - String uri = String.format("%s://%s%s", gatewayConfigProperties.getScheme(), - gatewayConfigProperties.getHostname(), authConfigurationProperties.getGatewayQueryEndpoint()); + String uri = UrlUtils.getUrl(gatewayConfigProperties.getScheme(), gatewayConfigProperties.getHostname()) + + authConfigurationProperties.getGatewayQueryEndpoint(); String cookie = String.format("%s=%s", authConfigurationProperties.getCookieProperties().getCookieName(), token); try { @@ -126,8 +127,8 @@ public QueryResponse query(String token) { @Override public QueryResponse verifyOidc(String token) { ServiceAddress gatewayConfigProperties = gatewayClient.getGatewayConfigProperties(); - String uri = String.format("%s://%s%s", gatewayConfigProperties.getScheme(), - gatewayConfigProperties.getHostname(), authConfigurationProperties.getGatewayOidcValidateEndpoint()); + String uri = UrlUtils.getUrl(gatewayConfigProperties.getScheme(), gatewayConfigProperties.getHostname()) + + authConfigurationProperties.getGatewayOidcValidateEndpoint(); try { HttpPost post = new HttpPost(uri); diff --git a/zaas-service/src/main/java/org/zowe/apiml/zaas/cache/CachingServiceClient.java b/zaas-service/src/main/java/org/zowe/apiml/zaas/cache/CachingServiceClient.java index 91339e0ff6..779664d55f 100644 --- a/zaas-service/src/main/java/org/zowe/apiml/zaas/cache/CachingServiceClient.java +++ b/zaas-service/src/main/java/org/zowe/apiml/zaas/cache/CachingServiceClient.java @@ -25,6 +25,7 @@ import org.springframework.web.client.RestTemplate; import org.zowe.apiml.product.gateway.GatewayClient; import org.zowe.apiml.product.instance.ServiceAddress; +import org.zowe.apiml.util.UrlUtils; import java.util.Map; @@ -67,7 +68,7 @@ private String getGatewayAddress() { if (gatewayAddress.getScheme() == null || gatewayAddress.getHostname() == null) { throw new IllegalStateException("zaasProtocolHostPort has to have value in format ://: and not be null"); } - return String.format("%s://%s", gatewayAddress.getScheme(), gatewayAddress.getHostname()); + return UrlUtils.getUrl(gatewayAddress.getScheme(), gatewayAddress.getHostname()); } /**