Skip to content
Draft
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
2 changes: 2 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ jobs:
APIML_SECURITY_AUTH_PASSTICKET_CUSTOMUSERHEADER: customUserHeader
APIML_SECURITY_AUTH_PASSTICKET_CUSTOMAUTHHEADER: customPassticketHeader
ZWE_CONFIGS_APIML_SERVICE_ADDITIONALREGISTRATION_0_DISCOVERYSERVICEURLS: https://discovery-service-2:10011/eureka
APIML_SERVICE_CORSENABLED: true
APIML_SERVICE_CORSDEFAULTALLOWEDORIGINS: https://localhost:10010,https://localhost2:10010
mock-services:
image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }}
metrics-service:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.context.annotation.Profile;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -37,7 +36,6 @@
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
@ActiveProfiles("ResponseHeaderFixTest")
@DirtiesContext
class ResponseHeaderFixTest {

private static final int ADD_HEADER = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.zowe.apiml.apicatalog.ApiCatalogApplication;
Expand All @@ -47,7 +46,6 @@
class AttlsConfigTest {

@Nested
@DirtiesContext
@ActiveProfiles({"AttlsConfigTestCatalog", "attlsServer", "attlsClient"})
class GivenAttlsModeEnabled extends ApiCatalogFunctionalTest {

Expand Down Expand Up @@ -103,7 +101,6 @@ void requestFailsWithAttlsContextReasonWithHttp() {
}
)
@ActiveProfiles({"attlsServer", "attlsClient", "debug"})
@DirtiesContext
@SpringBootTest(
classes = ApiCatalogApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
Expand Down
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ subprojects {

tasks.withType(Test) {
maxParallelForks = 1
maxHeapSize = '2g'
systemProperty 'spring.test.context.cache.maxSize', '5'
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.context.annotation.Profile;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -43,7 +42,6 @@
)
@ActiveProfiles("ResponseHeaderFixTest")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@DirtiesContext
class ResponseHeaderFixTest {

private static final int ADD_HEADER = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.zowe.apiml.caching.CachingService;
Expand Down Expand Up @@ -60,7 +59,6 @@ private String getUri(String hostname, int port, String scheme) {
"caching.storage.mode=inMemory"
}
)
@DirtiesContext
@Nested
class GivenAttlsModeEnabled {

Expand Down Expand Up @@ -131,7 +129,6 @@ void requestFailsWithAttlsReasonWithHttp() {
}
)
@ActiveProfiles({"attlsServer", "attlsClient"})
@DirtiesContext
@SpringBootTest(
classes = CachingService.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
Expand Down
2 changes: 0 additions & 2 deletions cloud-gateway-package/src/main/resources/bin/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,6 @@ _BPX_JOBNAME=${ZWE_zowe_job_prefix}${CLOUD_GATEWAY_CODE} java \
-Dapiml.service.hostname=${ZWE_haInstance_hostname:-localhost} \
-Dapiml.service.port=${ZWE_configs_port:-10023} \
-Dapiml.service.forwardClientCertEnabled=${ZWE_configs_apiml_service_forwardClientCertEnabled:-false} \
-Dapiml.service.corsEnabled=${ZWE_configs_apiml_service_corsEnabled:-false} \
-Dapiml.service.corsAllowedMethods=${ZWE_configs_apiml_service_corsAllowedMethods:-} \
-Dapiml.security.x509.registry.allowedUsers=${ZWE_configs_apiml_security_x509_registry_allowedUsers:-} \
-Dapiml.logs.location=${ZWE_zowe_logDirectory} \
-Dapiml.zoweManifest=${ZWE_zowe_runtimeDirectory}/manifest.json \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public class ConnectionsConfig {
private int requestTimeout;

@Value("${apiml.service.corsEnabled:false}")
private boolean corsEnabled;
private boolean gatewayCorsEnabled;

@Value("${apiml.service.corsAllowedMethods:GET,HEAD,POST,PATCH,DELETE,PUT,OPTIONS}")
private List<String> corsAllowedMethods;
Expand Down Expand Up @@ -356,7 +356,10 @@ public CorsConfigurationSource corsConfigurationSource(RoutePredicateHandlerMapp

@Bean
public CorsUtils corsUtils() {
return new CorsUtils(corsEnabled, corsAllowedMethods, null);
return CorsUtils.builder()
.gatewayCorsEnabled(gatewayCorsEnabled)
.defaultAllowedCorsHttpMethods(corsAllowedMethods)
.build();
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,9 @@ void setAuth(ServiceInstance serviceInstance, RouteDefinition routeDefinition, A

void setCors(ServiceInstance serviceInstance) {
corsUtils.setCorsConfiguration(
serviceInstance.getServiceId().toLowerCase(),
serviceInstance.getMetadata(),
(prefix, serviceId, config) -> {
serviceId = serviceInstance.getMetadata().getOrDefault(APIML_ID, serviceInstance.getServiceId().toLowerCase());
(prefix, config) -> {
String serviceId = serviceInstance.getMetadata().getOrDefault(APIML_ID, serviceInstance.getServiceId().toLowerCase());
getCorsConfigurationSource().registerCorsConfiguration("/" + serviceId + "/**", config);
});
}
Expand Down Expand Up @@ -176,9 +175,6 @@ public Flux<RouteDefinition> getRouteDefinitions() {
AtomicInteger order = new AtomicInteger();
// iterate over services
return getServiceInstances().flatMap(Flux::fromIterable).map(serviceInstance -> {
// configure CORS for the service (if necessary)
setCors(serviceInstance);

// generate route definition per services and its routing rules
return getAuthFilterPerRoute(order, serviceInstance, getPostRoutingFilters(serviceInstance));
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package org.zowe.apiml.cloudgatewayservice.acceptance;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.zowe.apiml.cloudgatewayservice.acceptance.common.AcceptanceTest;
import org.zowe.apiml.cloudgatewayservice.acceptance.common.AcceptanceTestWithMockServices;
Expand All @@ -27,6 +28,7 @@ class CorsPerServiceTest extends AcceptanceTestWithMockServices {
private static final String HEADER_X_FORWARD_TO = "X-Forward-To";

@Test
@Disabled("CORS Not supported in SCGW. Using Spring's defaults")
void routeToServiceWithCorsEnabled() throws IOException {
mockService("serviceid1")
.addEndpoint("/test")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@
@Retention(RetentionPolicy.RUNTIME)
@ComponentScan(basePackages = "org.zowe.apiml.cloudgatewayservice")
@SpringBootTest(classes = CloudGatewayServiceTestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {"management.server.port=10091","server.internal.enabled=false"})
properties = {
"management.server.port=-1",
"server.internal.enabled=false"
}
)
@Import(DiscoveryClientTestConfig.class)
@DirtiesContext
public @interface AcceptanceTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.springframework.test.util.ReflectionTestUtils;
import org.zowe.apiml.util.CorsUtils;

import java.lang.reflect.Field;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -133,10 +132,8 @@ public class WhenCorsAllowedMethodsIsNotSet {
@Test
void validateDefaultCorsAllowedMethods() throws NoSuchFieldException, IllegalAccessException {
CorsUtils corsUtils = connectionsConfig.corsUtils();

Field field = corsUtils.getClass().getDeclaredField("allowedCorsHttpMethods");
field.setAccessible(true);
List<String> corsAllowedMethods = (List<String>) field.get(corsUtils);
@SuppressWarnings("unchecked")
List<String> corsAllowedMethods = (List<String>) ReflectionTestUtils.getField(corsUtils, "defaultAllowedCorsHttpMethods");
assertEquals(7, corsAllowedMethods.size());
}
}
Expand All @@ -155,9 +152,8 @@ public class WhenCorsAllowedMethodsIsSet {
void validateCorsAllowedMethods() throws NoSuchFieldException, IllegalAccessException {
CorsUtils corsUtils = connectionsConfig.corsUtils();

Field field = corsUtils.getClass().getDeclaredField("allowedCorsHttpMethods");
field.setAccessible(true);
List<String> corsAllowedMethods = (List<String>) field.get(corsUtils);
@SuppressWarnings("unchecked")
List<String> corsAllowedMethods = (List<String>) ReflectionTestUtils.getField(corsUtils, "defaultAllowedCorsHttpMethods");
assertEquals(3, corsAllowedMethods.size());
assertEquals("GET", corsAllowedMethods.get(0));
assertEquals("POST", corsAllowedMethods.get(1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

package org.zowe.apiml.cloudgatewayservice.service;

import org.apache.logging.log4j.util.TriConsumer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
Expand All @@ -27,17 +26,32 @@
import org.zowe.apiml.auth.AuthenticationScheme;
import org.zowe.apiml.cloudgatewayservice.service.routing.RouteDefinitionProducer;
import org.zowe.apiml.cloudgatewayservice.service.scheme.SchemeHandler;
import org.zowe.apiml.eurekaservice.client.util.EurekaMetadataParser;
import org.zowe.apiml.product.routing.RoutedService;
import org.zowe.apiml.util.CorsUtils;
import reactor.core.publisher.Flux;

import java.util.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.zowe.apiml.constants.EurekaMetadataDefinition.APIML_ID;
import static org.zowe.apiml.constants.EurekaMetadataDefinition.SERVICE_SUPPORTING_CLIENT_CERT_FORWARDING;

Expand Down Expand Up @@ -101,7 +115,6 @@ private static SchemeHandler createSchemeHandler(AuthenticationScheme type) {
}

private static RouteDefinitionProducer createRouteDefinitionProducer(int order, String id) {
EurekaMetadataParser metadataParser = new EurekaMetadataParser();
RouteDefinitionProducer rdp = mock(RouteDefinitionProducer.class);
doReturn(order).when(rdp).getOrder();
doAnswer(answer -> {
Expand Down Expand Up @@ -163,31 +176,32 @@ void givenExistingAuthenticationScheme_whenSetAuth_thenCallApply() {
verify(SCHEME_HANDLER_FILTERS[0]).apply(MOCK_SERVICE, routeDefinition, authentication);
}

private TriConsumer<String, String, CorsConfiguration> getCorsLambda(Consumer<Map<String, String>> metadataProcessor) {
@SuppressWarnings("unchecked")
private BiConsumer<String, CorsConfiguration> getCorsLambda(Consumer<Map<String, String>> metadataProcessor) {
ServiceInstance serviceInstance = createServiceInstance("myservice", "api/v1");
metadataProcessor.accept(serviceInstance.getMetadata());

routeLocator.setCors(serviceInstance);
ArgumentCaptor<TriConsumer<String, String, CorsConfiguration>> lambdaCaptor = ArgumentCaptor.forClass(TriConsumer.class);
verify(corsUtils).setCorsConfiguration(anyString(), any(), lambdaCaptor.capture());
ArgumentCaptor<BiConsumer<String, CorsConfiguration>> lambdaCaptor = ArgumentCaptor.forClass(BiConsumer.class);
verify(corsUtils).setCorsConfiguration(any(), lambdaCaptor.capture());

return lambdaCaptor.getValue();
}

@Test
void givenApimlId_whenSetCors_thenServiceIdIsReplacedWithApimlId() {
TriConsumer<String, String, CorsConfiguration> corsLambda = getCorsLambda(md -> md.put(APIML_ID, "apimlid"));
BiConsumer<String, CorsConfiguration> corsLambda = getCorsLambda(md -> md.put(APIML_ID, "apimlid"));

corsLambda.accept(null, "myservice", null);
corsLambda.accept("myservice", null);

verify(urlBasedCorsConfigurationSource).registerCorsConfiguration("/apimlid/**", null);
}

@Test
void givenNoApimlId_whenSetCors_thenServiceIdIsUsed() {
TriConsumer<String, String, CorsConfiguration> corsLambda = getCorsLambda(md -> {});
BiConsumer<String, CorsConfiguration> corsLambda = getCorsLambda(md -> {});

corsLambda.accept(null, "myservice", null);
corsLambda.accept("myservice", null);

verify(urlBasedCorsConfigurationSource).registerCorsConfiguration("/myservice/**", null);
}
Expand Down Expand Up @@ -245,7 +259,6 @@ void givenRouteLocator_whenGetRouteDefinitions_thenGenerateAll() {

int index = 0;
for (String serviceId : new String[] {"service1", "service2"}) {
verify(corsUtils).setCorsConfiguration(eq(serviceId), any(), any());

for (String gatewayUrl : new String[] {"a/b", ""}) {
for (String producerId : new String[] {"id0", "id5", "id10"}) {
Expand Down
2 changes: 0 additions & 2 deletions cloud-gateway-service/src/test/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ apiml:
port: 10023
hostname: localhost
scheme: https
corsEnabled: true
ignoredHeadersWhenCorsEnabled: Access-Control-Request-Method,Access-Control-Request-Headers,Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Headers,Access-Control-Allow-Credentials,Origin
cloudGateway:
serviceRegistryEnabled: false
forwardClientCertEnabled: false
Expand Down
Loading
Loading