Skip to content

Commit

Permalink
Merge branch 'v3.x.x' into reboot/v3-debug-improvements-25-01-30
Browse files Browse the repository at this point in the history
  • Loading branch information
pablocarle authored Feb 3, 2025
2 parents df2e88c + 6331469 commit 0b1349a
Show file tree
Hide file tree
Showing 50 changed files with 817 additions and 478 deletions.
2 changes: 1 addition & 1 deletion api-catalog-ui/frontend/.env
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ REACT_APP_STATUS_UPDATE_MAX_RETRIES=10
REACT_APP_STATUS_UPDATE_DEBOUNCE=300
REACT_APP_CA_ENV=false
REACT_APP_STATUS_UPDATE_SCALING_DURATION=1000
REACT_APP_ZOWE_BUILD_INFO=3.1.6-SNAPSHOT
REACT_APP_ZOWE_BUILD_INFO=3.1.7-SNAPSHOT
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package org.zowe.apiml.security.common.auth.saf;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;

import java.lang.invoke.MethodHandle;
Expand Down Expand Up @@ -96,6 +97,9 @@ private boolean checkPermission(String userId, String resourceType, String resou
@Override
public boolean hasSafResourceAccess(Authentication authentication, String resourceClass, String resourceName, String accessLevel) {
String userid = authentication.getName();
if (StringUtils.isEmpty(userid)) {
return false;
}
AccessLevel level = AccessLevel.valueOf(accessLevel);
log.debug("Evaluating access of user {} to resource {} in class {} level {}", userid, resourceClass, resourceName, level);
return checkPermission(userid, resourceClass, resourceName, level.getValue(), true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ void testHasSafResourceAccess_whenNoResponse_thenTrue() {
assertTrue(safResourceAccessVerifying.hasSafResourceAccess(authentication, CLASS, RESOURCE, LEVEL.name()));
}

@Test
void testHasSafResourceAccess_whenUseridEmpty_thenFalse() {
assertFalse(safResourceAccessVerifying.hasSafResourceAccess(new UsernamePasswordAuthenticationToken("", "token"), CLASS, RESOURCE, LEVEL.name()));
}

@Builder
public static class TestPlatformReturned {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public enum ErrorCode {
ERR_8_12_16(8, 12, 16, HttpStatus.SC_INTERNAL_SERVER_ERROR, "Invocation of the Security Server Network Authentication Service Program Call (PC) interface failed with a 'local services are not available' return code. This indicates that the Security Server Network Authentication Service started task (SKRBKDC) address space has not been started or is terminating."),
ERR_8_12_20(8, 12, 20, HttpStatus.SC_INTERNAL_SERVER_ERROR, "Invocation of the Security Server Network Authentication Service Program Call (PC) interface failed with an 'abend in the PC service routine' return code. The symptom record associated with this abend can be found in the logrec data set."),
ERR_8_12_24(8, 12, 24, HttpStatus.SC_INTERNAL_SERVER_ERROR, "Invocation of the Security Server Network Authentication Service Program Call (PC) interface failed with an 'unable to obtain control lock' return code. This can occur if the task holding the lock is not being dispatched (for example, a dump is in progress)."),
ERR_8_16_28(8, 16, 28, HttpStatus.SC_BAD_REQUEST, "Unable to generate PassTicket. Verify that the secured signon (PassTicket) function and application ID is configured properly by referring to Using PassTickets in z/OS Security Server RACF Security Administrator's Guide."),
ERR_8_16_28(8, 16, 28, HttpStatus.SC_INTERNAL_SERVER_ERROR, "Unable to generate PassTicket. Verify that the secured signon (PassTicket) function and application ID is configured properly by referring to Using PassTickets in z/OS Security Server RACF Security Administrator's Guide."),
ERR_8_16_32(8, 16, 32, HttpStatus.SC_INTERNAL_SERVER_ERROR, "PassTicket evaluation failure. Possible reasons include: " +
"PassTicket to be evaluated is not a successful PassTicket. "
+ "The PassTicket to be evaluated was already evaluated before and replay protection is in effect. "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void testErrorCode() {

te = new TestException(8, 16, 28);
assertSame(AbstractIRRPassTicketException.ErrorCode.ERR_8_16_28, te.getErrorCode());
assertEquals(HttpStatus.SC_BAD_REQUEST, te.getHttpStatus());
assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, te.getHttpStatus());
}

class TestException extends AbstractIRRPassTicketException {
Expand Down
4 changes: 4 additions & 0 deletions config/local/gateway-service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ eureka:
serviceUrl:
defaultZone: https://localhost:10011/eureka/
server:
webSocket:
requestBufferSize: 16348
max-http-request-header-size: 16348

ssl:
keyAlias: localhost
keyPassword: password
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ artifactoryPublishingMavenRepo=https://zowe.jfrog.io/zowe/libs-release-local
artifactoryPublishingMavenSnapshotRepo=https://zowe.jfrog.io/zowe/libs-snapshot-local

# Artifacts version
version=3.1.6-SNAPSHOT
version=3.1.7-SNAPSHOT

defaultSpringBootVersion=2.0.2.RELEASE
defaultSpringBootCloudVersion=2.0.0.RELEASE
Expand Down
67 changes: 61 additions & 6 deletions integration-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ test {

task startUpCheck(type: Test) {
group 'integration tests'
description "Check that the API Mediation Layer is up and runnig"
description "Check that the API Mediation Layer is up and running"

systemProperties System.properties
useJUnitPlatform {
Expand All @@ -97,7 +97,6 @@ task environmentCheck(type: Test) {
outputs.upToDateWhen { false }
}


task runStartUpCheck(type: Test) {
group 'integration tests'
description "Check that the API Mediation Layer is up and running"
Expand Down Expand Up @@ -170,14 +169,14 @@ task runAllIntegrationTests(type: Test) {
outputs.upToDateWhen { false }
}

task runAllIntegrationTestsForZoweTestingOnZos(type: Test) {
task runAllIntegrationTestsForZoweNonHaTestingOnZos(type: Test) {
// This task is intended to run on z/OS systems with some limitations:
// Only 1 Gateway
// Only 1 Gateway (Non-HA mode)
// z/OSMF Authentication provider only
// No support for SAF ID Tokens

group "Integration tests"
description "Run all integration tests for Zowe testing on z/OS (limited)"
description "Run all integration tests for Zowe Non-HA testing on z/OS (limited)"

def targetSystem = System.getenv("ZOS_TARGET_SYS") ? "-" + System.getenv("ZOS_TARGET_SYS") : ""
systemProperty "environment.config", targetSystem
Expand All @@ -203,9 +202,60 @@ task runAllIntegrationTestsForZoweTestingOnZos(type: Test) {
'SafIdTokenTest'
)
}

debugOptions {
port = 5005
suspend = true
server = true
}
outputs.upToDateWhen { false }
}

task runAllIntegrationTestsForZoweHaTestingOnZos(type: Test) {
// This task is intended to run on z/OS systems with some limitations:
// More than 1 Gateway (HA mode)
// z/OSMF Authentication provider only
// No support for SAF ID Tokens

group "Integration tests"
description "Run all integration tests for Zowe HA testing on z/OS (limited)"

def targetSystem = System.getenv("ZOS_TARGET_SYS") ? "-" + System.getenv("ZOS_TARGET_SYS") : ""
systemProperty "environment.config", targetSystem
systemProperty "environment.zos.target", "true"
systemProperty "environment.ha", true
systemProperties System.properties
systemProperties.remove('java.endorsed.dirs')

useJUnitPlatform {
excludeTags(
'StartupCheck',
'EnvironmentCheck',
'AdditionalLocalTest',
'TestsNotMeantForZowe',
'DiscoverableClientDependentTest',
'OktaOauth2Test',
'MultipleRegistrationsTest',
'NotForMainframeTest',
'ApiCatalogStandaloneTest',
'SAFProviderTest',
'GatewayProxyTest',
'SafIdTokenTest',
'ChaoticHATest',
'GraphQLTest'
)
}

debugOptions {
port = 5005
suspend = true
server = true
}

outputs.upToDateWhen { false }
outputs.cacheIf { false }
}

task runAllIntegrationTestsForZoweTesting(type: Test) {
group "Integration tests"
description "Run all integration tests for Zowe testing"
Expand Down Expand Up @@ -350,6 +400,7 @@ task runGatewayProxyTest(type: Test) {
)
}
}

task runGatewayServiceRoutingTest(type: Test) {
group "integration tests"
description "Run tests verifying central gateway can locate service and translate auth scheme"
Expand Down Expand Up @@ -521,9 +572,13 @@ task runChaoticHATests(type: Test) {
group "Integration tests"
description "Run Chaotic tests verifying High Availability"

def targetSystem = System.getenv("ZOS_TARGET_SYS") ? "-" + System.getenv("ZOS_TARGET_SYS") : ""
systemProperty "environment.config", targetSystem
systemProperty "environment.zos.target", "true"
systemProperty "environment.ha", true

outputs.cacheIf { false }

systemProperty "environment.ha", true
systemProperties System.getProperties()
useJUnitPlatform {
includeTags(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.springframework.http.MediaType;
import org.zowe.apiml.util.TestWithStartedInstances;
import org.zowe.apiml.util.categories.CatalogTest;
Expand All @@ -33,12 +34,16 @@

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
import java.util.stream.Stream;

import static io.restassured.RestAssured.given;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
Expand All @@ -47,27 +52,34 @@
import static org.zowe.apiml.util.http.HttpRequestUtils.getUriFromGateway;

@CatalogTest
@TestInstance(Lifecycle.PER_CLASS)
class ApiCatalogEndpointIntegrationTest implements TestWithStartedInstances {

private static final String GET_ALL_CONTAINERS_ENDPOINT = "/apicatalog/api/v1/containers";
private static final String GET_CONTAINER_BY_ID_ENDPOINT = "/apicatalog/api/v1/containers/apimediationlayer";
private static final String GET_CONTAINER_BY_INVALID_ID_ENDPOINT = "/apicatalog/api/v1/containers/bad";
private static final String GET_API_CATALOG_API_DOC_DEFAULT_ENDPOINT = "/apicatalog/api/v1/apidoc/apicatalog";
private static final String GET_API_CATALOG_API_DOC_ENDPOINT = "/apicatalog/api/v1/apidoc/apicatalog/zowe.apiml.apicatalog v1.0.0";
private static final String INVALID_API_CATALOG_API_DOC_ENDPOINT = "/apicatalog/api/v1/apidoc/apicatalog/zowe.apiml.apicatalog v18.0.0";

private final static String UNAUTHORIZED_USERNAME = ConfigReader.environmentConfiguration().getAuxiliaryUserList().getCredentials("servicesinfo-unauthorized").get(0).getUser();
private final static String UNAUTHORIZED_PASSWORD = ConfigReader.environmentConfiguration().getAuxiliaryUserList().getCredentials("servicesinfo-unauthorized").get(0).getPassword();
private final static String USERNAME = ConfigReader.environmentConfiguration().getAuxiliaryUserList().getCredentials("servicesinfo-authorized").get(0).getUser();
private final static String PASSWORD = ConfigReader.environmentConfiguration().getAuxiliaryUserList().getCredentials("servicesinfo-authorized").get(0).getPassword();
private static final String UNAUTHORIZED_USERNAME = ConfigReader.environmentConfiguration().getAuxiliaryUserList().getCredentials("servicesinfo-unauthorized").get(0).getUser();
private static final String UNAUTHORIZED_PASSWORD = ConfigReader.environmentConfiguration().getAuxiliaryUserList().getCredentials("servicesinfo-unauthorized").get(0).getPassword();
private static final String USERNAME = ConfigReader.environmentConfiguration().getAuxiliaryUserList().getCredentials("servicesinfo-authorized").get(0).getUser();
private static final String PASSWORD = ConfigReader.environmentConfiguration().getAuxiliaryUserList().getCredentials("servicesinfo-authorized").get(0).getPassword();

private final List<String> baseHosts = new ArrayList<>();
private String validGatewayToken;
private String unauthorizedGatewayToken;

private String baseHost;
@BeforeAll
void init() {
validGatewayToken = gatewayToken(USERNAME, PASSWORD);
unauthorizedGatewayToken = gatewayToken(UNAUTHORIZED_USERNAME, UNAUTHORIZED_PASSWORD);

@BeforeEach
void setUp() {
GatewayServiceConfiguration gatewayServiceConfiguration = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration();
String host = gatewayServiceConfiguration.getHost();
int port = gatewayServiceConfiguration.getExternalPort();
baseHost = host + ":" + port;
Stream.of(gatewayServiceConfiguration.getHost().split(","))
.forEach(host -> baseHosts.add(host + ":" + port));
}

@Nested
Expand Down Expand Up @@ -138,7 +150,9 @@ void whenSpecificCatalogApiDoc() throws Exception {
// Then
assertFalse(paths.isEmpty(), apiCatalogSwagger);
assertFalse(componentSchemas.isEmpty(), apiCatalogSwagger);
assertEquals("https://" + baseHost + "/apicatalog/api/v1", swaggerServer, apiCatalogSwagger);
assertThat(apiCatalogSwagger, baseHosts.stream()
.map(host -> "https://" + host + "/apicatalog/api/v1")
.toList(), hasItem(equalTo(swaggerServer)));
assertNull(paths.get("/status/updates"), apiCatalogSwagger);
assertNotNull(paths.get("/containers/{id}"), apiCatalogSwagger);
assertNotNull(paths.get("/containers"), apiCatalogSwagger);
Expand Down Expand Up @@ -171,7 +185,9 @@ void whenDefaultCatalogApiDoc() throws Exception {
// Then
assertFalse(paths.isEmpty(), apiCatalogSwagger);
assertFalse(componentSchemas.isEmpty(), apiCatalogSwagger);
assertEquals("https://" + baseHost + "/apicatalog/api/v1", swaggerServer, apiCatalogSwagger);
assertThat(apiCatalogSwagger, baseHosts.stream()
.map(host -> "https://" + host + "/apicatalog/api/v1")
.toList(), hasItem(equalTo(swaggerServer)));
assertNull(paths.get("/status/updates"), apiCatalogSwagger);
assertNotNull(paths.get("/containers/{id}"), apiCatalogSwagger);
assertNotNull(paths.get("/containers"), apiCatalogSwagger);
Expand All @@ -197,35 +213,36 @@ class StaticApis {
private static final String STATIC_DEFINITION_GENERATE_ENDPOINT = "/apicatalog/api/v1/static-api/generate";
private static final String STATIC_DEFINITION_DELETE_ENDPOINT = "/apicatalog/api/v1/static-api/delete";
private static final String REFRESH_STATIC_APIS_ENDPOINT = "/apicatalog/api/v1/static-api/refresh";
private String staticDefinitionServiceId = "a" + UUID.randomUUID().toString().replace("-", "").substring(0, 10);
private final String staticDefinitionServiceId = "a" + UUID.randomUUID().toString().replace("-", "").substring(0, 10);
private final String staticDefinitionServiceIdUnauthorized = "una" + UUID.randomUUID().toString().replace("-", "").substring(0, 10);

@AfterAll
void cleanupStaticDefinition() {
given().relaxedHTTPSValidation()
.when()
.header("Service-Id", staticDefinitionServiceId)
.cookie(COOKIE_NAME, gatewayToken())
.cookie(COOKIE_NAME, validGatewayToken)
.delete(getUriFromGateway(STATIC_DEFINITION_DELETE_ENDPOINT));
}

@Test
@Order(1)
void whenCallStaticApiRefresh_thenResponseOk() throws IOException {
getStaticApiResponse(REFRESH_STATIC_APIS_ENDPOINT, null, HttpStatus.SC_OK, null, gatewayToken(USERNAME, PASSWORD));
getStaticApiResponse(REFRESH_STATIC_APIS_ENDPOINT, null, HttpStatus.SC_OK, null, validGatewayToken);
}

@Test
@Order(30)
void whenCallStaticDefinitionGenerate_thenResponse201() throws IOException {
String json = "# Dummy content";
getStaticApiResponse(STATIC_DEFINITION_GENERATE_ENDPOINT, staticDefinitionServiceId, HttpStatus.SC_CREATED, json, gatewayToken(USERNAME, PASSWORD));
getStaticApiResponse(STATIC_DEFINITION_GENERATE_ENDPOINT, staticDefinitionServiceId, HttpStatus.SC_CREATED, json, validGatewayToken);
}

@Test
@Order(31)
void whenCallStaticDefinitionGenerateWithUnauthorizedUser_thenResponse403() throws IOException {
String json = "# Dummy content";
getStaticApiResponse(STATIC_DEFINITION_GENERATE_ENDPOINT, staticDefinitionServiceId, HttpStatus.SC_FORBIDDEN, json, gatewayToken(UNAUTHORIZED_USERNAME, UNAUTHORIZED_PASSWORD));
getStaticApiResponse(STATIC_DEFINITION_GENERATE_ENDPOINT, staticDefinitionServiceIdUnauthorized, HttpStatus.SC_FORBIDDEN, json, unauthorizedGatewayToken);
}

private Response getStaticApiResponse(String endpoint, String definitionFileName, int returnCode, String body, String JWT) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import static io.restassured.http.ContentType.JSON;
import static org.apache.http.HttpStatus.*;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.isEmptyString;
import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.zowe.apiml.security.SecurityUtils.readPassword;
Expand Down Expand Up @@ -60,7 +60,7 @@ void doLoginWithValidBodyLoginRequest() {
.post(LOGIN_ENDPOINT_URL)
.then()
.statusCode(is(SC_NO_CONTENT))
.cookie(COOKIE_NAME, not(isEmptyString()))
.cookie(COOKIE_NAME, not(is(emptyString())))
.extract().detailedCookie(COOKIE_NAME);
}

Expand Down
Loading

0 comments on commit 0b1349a

Please sign in to comment.