From dfee107419f6bb3ed469482333cf6fecd150612e Mon Sep 17 00:00:00 2001 From: nx673747 Date: Thu, 27 Feb 2025 01:07:07 +0100 Subject: [PATCH 01/21] fix integration tests on zOS Signed-off-by: nx673747 --- .../schemes/CloudGatewayAuthTest.java | 39 +-- .../org/zowe/apiml/util/SecurityUtils.java | 255 ++++++++++-------- .../apiml/util/http/HttpRequestUtils.java | 48 ++-- .../util/requests/ApiCatalogRequests.java | 29 +- 4 files changed, 217 insertions(+), 154 deletions(-) diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/CloudGatewayAuthTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/CloudGatewayAuthTest.java index 4f03f7e363..34d56e1925 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/CloudGatewayAuthTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/CloudGatewayAuthTest.java @@ -37,16 +37,23 @@ import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.when; -import static org.junit.jupiter.api.Assertions.*; -import static org.zowe.apiml.util.SecurityUtils.*; -import static org.zowe.apiml.util.requests.Endpoints.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.zowe.apiml.util.SecurityUtils.generateJwtWithRandomSignature; +import static org.zowe.apiml.util.SecurityUtils.personalAccessToken; +import static org.zowe.apiml.util.SecurityUtils.validOktaAccessToken; import static org.zowe.apiml.util.requests.Endpoints.REQUEST_INFO_ENDPOINT; +import static org.zowe.apiml.util.requests.Endpoints.SAF_IDT_REQUEST; +import static org.zowe.apiml.util.requests.Endpoints.ZOSMF_REQUEST; +import static org.zowe.apiml.util.requests.Endpoints.ZOWE_JWT_REQUEST; @ZaasTest public class CloudGatewayAuthTest implements TestWithStartedInstances { - private static final CloudGatewayConfiguration conf = ConfigReader.environmentConfiguration().getCloudGatewayConfiguration(); - private static final SafIdtConfiguration safIdtConf = ConfigReader.environmentConfiguration().getSafIdtConfiguration(); + private static final CloudGatewayConfiguration GATEWAY_CONFIGURATION = ConfigReader.environmentConfiguration().getCloudGatewayConfiguration(); + private static final SafIdtConfiguration SAF_IDT_CONFIGURATION = ConfigReader.environmentConfiguration().getSafIdtConfiguration(); static Stream validToBeTransformed() { List arguments = new ArrayList<>(Arrays.asList( @@ -66,7 +73,7 @@ static Stream validToBeTransformed() { assertTrue(CollectionUtils.isEmpty(response.jsonPath().getList("certs"))); }) )); - if (safIdtConf.isEnabled()) { + if (SAF_IDT_CONFIGURATION.isEnabled()) { arguments.add(Arguments.of("SAF IDT auth scheme", SAF_IDT_REQUEST, (Consumer) response -> { assertNull(response.jsonPath().getString("cookies.jwtToken")); assertNotNull(response.jsonPath().getString("headers.x-saf-token")); @@ -90,7 +97,7 @@ static Stream noAuthTransformation() { Arguments.of("z/OSMF auth scheme", ZOSMF_REQUEST, assertions), Arguments.of("PassTicket auth scheme", REQUEST_INFO_ENDPOINT, assertions) )); - if (safIdtConf.isEnabled()) { + if (SAF_IDT_CONFIGURATION.isEnabled()) { arguments.add(Arguments.of("SAF IDT auth scheme", SAF_IDT_REQUEST, assertions)); } return arguments.stream(); @@ -116,7 +123,7 @@ void givenValidRequest_thenCredentialsAreTransformed(String title, String basePa Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + gatewayToken) .when() - .get(String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -130,7 +137,7 @@ void givenValidRequest_thenPatIsTransformed(String title, String basePath, Consu Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + pat) .when() - .get(String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -141,7 +148,7 @@ void givenValidRequest_thenClientCertIsTransformed(String title, String basePath Response response = given() .config(SslContext.clientCertValid) .when() - .get(String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -154,7 +161,7 @@ void givenValidRequest_thenOidcIsTransformed(String title, String basePath, Cons Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + oAuthToken) .when() - .get(String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -172,7 +179,7 @@ void givenInvalidPatRequest_thenPatIsNotTransformed(String title, String basePat Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + pat) .when() - .get(String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -183,7 +190,7 @@ void givenInvalidRequest_thenClientCertIsNotTransformed(String title, String bas Response response = given() .config(SslContext.selfSignedUntrusted) .when() - .get(String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -196,7 +203,7 @@ void givenInvalidRequest_thenOidcIsNotTransformed(String title, String basePath, Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + oAuthToken) .when() - .get(String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -205,7 +212,7 @@ void givenInvalidRequest_thenOidcIsNotTransformed(String title, String basePath, @MethodSource("org.zowe.apiml.integration.authentication.schemes.CloudGatewayAuthTest#noAuthTransformation") void givenNoCredentials_thenNoCredentialsAreProvided(String title, String basePath, Consumer assertions) { Response response = when() - .get(String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -216,7 +223,7 @@ void givenInvalidCredentials_thenNoCredentialsAreProvided(String title, String b Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer invalidToken") .when() - .get(String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } diff --git a/integration-tests/src/test/java/org/zowe/apiml/util/SecurityUtils.java b/integration-tests/src/test/java/org/zowe/apiml/util/SecurityUtils.java index 3a231759cb..931acff571 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/util/SecurityUtils.java +++ b/integration-tests/src/test/java/org/zowe/apiml/util/SecurityUtils.java @@ -18,26 +18,30 @@ import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import io.restassured.RestAssured; -import io.restassured.config.HttpClientConfig; import io.restassured.config.RestAssuredConfig; import io.restassured.config.SSLConfig; +import io.restassured.filter.log.LogDetail; import io.restassured.http.Cookie; -import io.restassured.response.Response; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHeaders; +import org.apache.http.ParseException; import org.apache.http.client.CookieStore; import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.client.utils.URIBuilder; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.ssl.SSLContexts; import org.apache.http.ssl.TrustStrategy; +import org.apache.http.util.EntityUtils; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; @@ -46,6 +50,7 @@ import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.json.JSONException; import org.json.JSONObject; import org.springframework.http.HttpStatus; import org.zowe.apiml.gateway.security.login.SuccessfulAccessTokenHandler; @@ -58,13 +63,13 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.net.URI; +import java.net.URISyntaxException; import java.security.Key; import java.security.KeyManagementException; import java.security.KeyPair; @@ -75,14 +80,12 @@ import java.security.NoSuchProviderException; import java.security.Security; import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Calendar; import java.util.Date; -import java.util.HashMap; +import java.util.Enumeration; import java.util.HashSet; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -103,30 +106,29 @@ import static org.zowe.apiml.util.requests.Endpoints.ZOSMF_AUTH_ENDPOINT; public class SecurityUtils { - public final static String GATEWAY_TOKEN_COOKIE_NAME = "apimlAuthenticationToken"; - - private final static GatewayServiceConfiguration serviceConfiguration = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration(); - private final static TlsConfiguration tlsConfiguration = ConfigReader.environmentConfiguration().getTlsConfiguration(); + public static final String GATEWAY_TOKEN_COOKIE_NAME = "apimlAuthenticationToken"; - private final static String gatewayScheme = serviceConfiguration.getScheme(); - private final static String gatewayHost = serviceConfiguration.getHost(); - private final static int gatewayPort = serviceConfiguration.getPort(); + private static final GatewayServiceConfiguration serviceConfiguration = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration(); + private static final TlsConfiguration tlsConfiguration = ConfigReader.environmentConfiguration().getTlsConfiguration(); - private final static String zosmfScheme = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getScheme(); - private final static String zosmfHost = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getHost(); - private final static int zosmfPort = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getPort(); + private static final String GATEWAY_SCHEME = serviceConfiguration.getScheme(); + private static final String GATEWAY_HOST = StringUtils.isBlank(serviceConfiguration.getDvipaHost()) ? serviceConfiguration.getHost() : serviceConfiguration.getDvipaHost(); + private static final int GATEWAY_PORT = serviceConfiguration.getPort(); - public final static String USERNAME = ConfigReader.environmentConfiguration().getCredentials().getUser(); - public final static String PASSWORD = ConfigReader.environmentConfiguration().getCredentials().getPassword(); + private static final String ZOSMF_SCHEME = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getScheme(); + private static final String ZOSMF_HOST = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getHost(); + private static final int ZOSMF_PORT = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getPort(); - public final static String OKTA_HOSTNAME = ConfigReader.environmentConfiguration().getIdpConfiguration().getHost(); - public final static String OKTA_CLIENT_ID = ConfigReader.environmentConfiguration().getOidcConfiguration().getClientId(); - public final static String OKTA_USER = ConfigReader.environmentConfiguration().getIdpConfiguration().getUser(); - public final static String OKTA_PASSWORD = ConfigReader.environmentConfiguration().getIdpConfiguration().getPassword(); - public final static String OKTA_ALT_USER = ConfigReader.environmentConfiguration().getIdpConfiguration().getAlternateUser(); - public final static String OKTA_ALT_PASSWORD = ConfigReader.environmentConfiguration().getIdpConfiguration().getAlternatePassword(); + public static final String USERNAME = ConfigReader.environmentConfiguration().getCredentials().getUser(); + public static final String PASSWORD = ConfigReader.environmentConfiguration().getCredentials().getPassword(); + public static final String OKTA_HOSTNAME = ConfigReader.environmentConfiguration().getIdpConfiguration().getHost(); + public static final String OKTA_CLIENT_ID = ConfigReader.environmentConfiguration().getOidcConfiguration().getClientId(); + public static final String OKTA_USER = ConfigReader.environmentConfiguration().getIdpConfiguration().getUser(); + public static final String OKTA_PASSWORD = ConfigReader.environmentConfiguration().getIdpConfiguration().getPassword(); + public static final String OKTA_ALT_USER = ConfigReader.environmentConfiguration().getIdpConfiguration().getAlternateUser(); + public static final String OKTA_ALT_PASSWORD = ConfigReader.environmentConfiguration().getIdpConfiguration().getAlternatePassword(); - public final static String COOKIE_NAME = "apimlAuthenticationToken"; + public static final String COOKIE_NAME = "apimlAuthenticationToken"; public static final String PAT_COOKIE_AUTH_NAME = "personalAccessToken"; protected static String getUsername() { @@ -136,11 +138,11 @@ protected static String getUsername() { //@formatter:off public static String getGatewayUrl(String path) { - return getGatewayUrl(path, gatewayPort); + return getGatewayUrl(path, GATEWAY_PORT); } public static String getGatewayUrl(String path, int port) { - return String.format("%s://%s:%d%s", gatewayScheme, gatewayHost, port, path); + return String.format("%s://%s:%d%s", GATEWAY_SCHEME, GATEWAY_HOST, port, path); } public static String getGatewayLogoutUrl(String path) { @@ -165,18 +167,20 @@ public static String gatewayToken(URI gatewayLoginEndpoint, String username, Str SSLConfig originalConfig = RestAssured.config().getSSLConfig(); RestAssured.config = RestAssured.config().sslConfig(getConfiguredSslConfig()); - String cookie = given() - .contentType(JSON) - .body(loginRequest) - .when() - .post(gatewayLoginEndpoint) - .then() - .statusCode(is(SC_NO_CONTENT)) - .cookie(GATEWAY_TOKEN_COOKIE_NAME, not(isEmptyString())) - .extract().cookie(GATEWAY_TOKEN_COOKIE_NAME); - - RestAssured.config = RestAssured.config().sslConfig(originalConfig); - return cookie; + try { + return given() + .contentType(JSON) + .body(loginRequest) + .when() + .post(gatewayLoginEndpoint) + .then() + .log().ifValidationFails(LogDetail.ALL) + .statusCode(is(SC_NO_CONTENT)) + .cookie(GATEWAY_TOKEN_COOKIE_NAME, not(isEmptyString())) + .extract().cookie(GATEWAY_TOKEN_COOKIE_NAME); + } finally{ + RestAssured.config = RestAssured.config().sslConfig(originalConfig); + } } /** @@ -230,7 +234,7 @@ public static String getZosmfTokenWebClient(String cookie) { CookieStore cookieStore = new BasicCookieStore(); context.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore); - HttpUriRequest request = new HttpPost(String.format("%s://%s:%d%s", zosmfScheme, zosmfHost, zosmfPort, ZOSMF_AUTH_ENDPOINT)); + HttpUriRequest request = new HttpPost(String.format("%s://%s:%d%s", ZOSMF_SCHEME, ZOSMF_HOST, ZOSMF_PORT, ZOSMF_AUTH_ENDPOINT)); request.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()); request.addHeader(HttpHeaders.AUTHORIZATION, String.format("Basic %s", java.util.Base64.getEncoder().encodeToString(String.format("%s:%s", USERNAME, PASSWORD).getBytes()))); request.addHeader("X-CSRF-ZOSMF-HEADER", "csrf"); @@ -258,27 +262,27 @@ public static String getZosmfTokenWebClient(String cookie) { * @return */ public static String getZosmfToken(String cookie) { - return getZosmfToken(String.format("%s://%s:%d%s", zosmfScheme, zosmfHost, zosmfPort, ZOSMF_AUTH_ENDPOINT), cookie, SC_OK); + return getZosmfToken(String.format("%s://%s:%d%s", ZOSMF_SCHEME, ZOSMF_HOST, ZOSMF_PORT, ZOSMF_AUTH_ENDPOINT), cookie, SC_OK); } private static String getZosmfToken(String url, String cookie, int expectedCode) { SSLConfig originalConfig = RestAssured.config().getSSLConfig(); RestAssured.config = RestAssured.config().sslConfig(getConfiguredSslConfig()); - String zosmfToken = given() - .contentType(JSON) - .auth().preemptive().basic(USERNAME, PASSWORD) - .header("X-CSRF-ZOSMF-HEADER", "") - .when() - .post(url) - .then() - .statusCode(is(expectedCode)) - .cookie(cookie, not(isEmptyString())) - .extract().cookie(cookie); - - RestAssured.config = RestAssured.config().sslConfig(originalConfig); - - return zosmfToken; + try { + return given() + .contentType(JSON) + .auth().preemptive().basic(USERNAME, PASSWORD) + .header("X-CSRF-ZOSMF-HEADER", "") + .when() + .post(url) + .then() + .statusCode(is(expectedCode)) + .cookie(cookie, not(isEmptyString())) + .extract().cookie(cookie); + } finally{ + RestAssured.config = RestAssured.config().sslConfig(originalConfig); + } } public static String generateZoweJwtWithLtpa(String ltpaToken) throws UnrecoverableKeyException, CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException { @@ -329,9 +333,18 @@ private static Key getKey() throws KeyStoreException, IOException, CertificateEx public static String getClientCertificate() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException { KeyStore ks = loadKeystore(SecurityUtils.tlsConfiguration.getClientKeystore()); - Certificate certificate = ks.getCertificate(ks.aliases().nextElement()); + String clientCN = SecurityUtils.tlsConfiguration.getClientCN(); + Enumeration aliases = ks.aliases(); - return Base64.encode(certificate.getEncoded()).toString(); + while (aliases.hasMoreElements()) { + X509Certificate certificate = (X509Certificate) ks.getCertificate(aliases.nextElement()); + if (certificate.getSubjectX500Principal().getName().contains("CN=" + clientCN)) { + return Base64.encode(certificate.getEncoded()).toString(); + } + } + + throw new IllegalArgumentException( + String.format("TlsConfiguration error: provided client CN: %s is not present in client keystore %s", clientCN, tlsConfiguration.getClientKeystore())); } public static String getDummyClientCertificate()throws CertificateException, NoSuchAlgorithmException, NoSuchProviderException, OperatorCreationException, IOException { @@ -375,17 +388,19 @@ public static String personalAccessToken(Set scopes) { SSLConfig originalConfig = RestAssured.config().getSSLConfig(); RestAssured.config = RestAssured.config().sslConfig(getConfiguredSslConfig()); - String token = given() - .contentType(JSON).header("Authorization", "Basic " + Base64.encode(USERNAME + ":" + PASSWORD)) - .body(accessTokenRequest) - .when() - .post(gatewayGenerateAccessTokenEndpoint) - .then() - .statusCode(is(SC_OK)) - .extract().body().asString(); - - RestAssured.config = RestAssured.config().sslConfig(originalConfig); - return token; + try { + return given() + .contentType(JSON).header("Authorization", "Basic " + Base64.encode(USERNAME + ":" + PASSWORD)) + .body(accessTokenRequest) + .when() + .post(gatewayGenerateAccessTokenEndpoint) + .then() + .log().ifValidationFails(LogDetail.ALL) + .statusCode(is(SC_OK)) + .extract().body().asString(); + } finally { + RestAssured.config = RestAssured.config().sslConfig(originalConfig); + } } public static String personalAccessTokenWithClientCert(RestAssuredConfig sslConfig) { @@ -396,16 +411,17 @@ public static String personalAccessTokenWithClientCert(RestAssuredConfig sslConf SuccessfulAccessTokenHandler.AccessTokenRequest accessTokenRequest = new SuccessfulAccessTokenHandler.AccessTokenRequest(60, scopes); SSLConfig originalConfig = RestAssured.config().getSSLConfig(); - String token = given().config(sslConfig) - .body(accessTokenRequest) - .when() - .post(gatewayGenerateAccessTokenEndpoint) - .then() - .statusCode(is(SC_OK)) - .extract().body().asString(); - - RestAssured.config = RestAssured.config().sslConfig(originalConfig); - return token; + try { + return given().config(sslConfig) + .body(accessTokenRequest) + .when() + .post(gatewayGenerateAccessTokenEndpoint) + .then() + .statusCode(is(SC_OK)) + .extract().body().asString(); + } finally { + RestAssured.config = RestAssured.config().sslConfig(originalConfig); + } } public static String validOktaAccessToken(boolean userHasMappingDefined) { @@ -421,47 +437,66 @@ public static String validOktaAccessToken(boolean userHasMappingDefined) { assertNotNull(sessionToken, "Failed to get session token from Okta authentication."); // retrieve the access token from Okta using session token - Map queryParams = new HashMap<>(); - queryParams.put("client_id", OKTA_CLIENT_ID); - queryParams.put("redirect_uri", "https://localhost:10010/login/oauth2/code/okta"); - queryParams.put("response_type", "token"); - queryParams.put("response_mode", "form_post"); - queryParams.put("sessionToken", sessionToken); - queryParams.put("scope", "openid"); - queryParams.put("state", "TEST"); - queryParams.put("nonce", "TEST"); - Response authResponse = given() - .config(RestAssured.config().httpClient(HttpClientConfig.httpClientConfig().setParam("http.connection.timeout", 30 * 1000))) - .queryParams(queryParams) - .when() - .get(OKTA_HOSTNAME + "/oauth2/v1/authorize") - .then() - .statusCode(200) - .extract().response(); - // The response is HTML form where access token is hidden input field (this is controlled by response_mode = form_post) + try (CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(getRelaxedSslContext()).build()) { + URIBuilder uriBuilder = new URIBuilder(OKTA_HOSTNAME + "/oauth2/v1/authorize"); + uriBuilder.setParameter("client_id", OKTA_CLIENT_ID); + uriBuilder.setParameter("redirect_uri", "https://localhost:10010/login/oauth2/code/okta"); + uriBuilder.setParameter("response_type", "token"); + uriBuilder.setParameter("response_mode", "form_post"); + uriBuilder.setParameter("sessionToken", sessionToken); + uriBuilder.setParameter("scope", "openid"); + uriBuilder.setParameter("state", "TEST"); + uriBuilder.setParameter("nonce", "TEST"); + HttpGet request = new HttpGet(uriBuilder.build()); + CloseableHttpResponse response = httpClient.execute(request); - String body = authResponse.getBody().asString(); - String accessToken = StringUtils.substringBetween(body, "name=\"access_token\" value=\"", "\"/>"); - assertNotNull(accessToken, "Failed to locate access token in the Okta /authorize response."); - return accessToken; + if (response.getStatusLine().getStatusCode() == 200) { + // The response is HTML form where access token is hidden input field (this is controlled by response_mode = form_post) + + String body = EntityUtils.toString(response.getEntity()); + String accessToken = StringUtils.substringBetween(body, "name=\"access_token\" value=\"", "\"/>"); + assertNotNull(accessToken, "Failed to locate access token in the Okta /authorize response."); + return accessToken; + } else { + throw new RuntimeException("Failed obtaining OKTA access token: " + response.getStatusLine().getStatusCode() + ": " + EntityUtils.toString(response.getEntity())); + } + } catch (IOException | URISyntaxException e) { + throw new RuntimeException(e); + } } private static String getOktaSession(String username, String password) { assertNotNull(username, "OKTA username is not set."); assertNotNull(password, "OKTA password is not set."); JSONObject requestBody = new JSONObject(); - requestBody.put("username", username); - requestBody.put("password", password); + try { + requestBody.put("username", username); + requestBody.put("password", password); + } catch (JSONException e) { + e.printStackTrace(); + } - return given() - .contentType(JSON) - .body(requestBody.toString()) - .when() - .post(OKTA_HOSTNAME + "/api/v1/authn") - .then() - .statusCode(200) - .extract().path("sessionToken"); + try (CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(getRelaxedSslContext()).build()) { + URIBuilder uriBuilder = new URIBuilder(OKTA_HOSTNAME + "/api/v1/authn"); + + HttpPost request = new HttpPost(uriBuilder.build()); + request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); + StringEntity entity = new StringEntity(requestBody.toString()); + request.setEntity(entity); + CloseableHttpResponse response = httpClient.execute(request); + + if (response.getStatusLine().getStatusCode() == 200) { + // The response is HTML form where access token is hidden input field (this is controlled by response_mode = form_post) + + String responseBody = EntityUtils.toString(response.getEntity()); + return new JSONObject(responseBody).getString("sessionToken"); + } else { + throw new RuntimeException("Failed obtaining OKTA access token: " + response.getStatusLine().getStatusCode() + ": " + EntityUtils.toString(response.getEntity())); + } + } catch (IOException | URISyntaxException | ParseException | JSONException e) { + throw new RuntimeException(e); + } } public static String expiredOktaAccessToken() { diff --git a/integration-tests/src/test/java/org/zowe/apiml/util/http/HttpRequestUtils.java b/integration-tests/src/test/java/org/zowe/apiml/util/http/HttpRequestUtils.java index 39a11809cb..fa3a9ce50a 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/util/http/HttpRequestUtils.java +++ b/integration-tests/src/test/java/org/zowe/apiml/util/http/HttpRequestUtils.java @@ -11,6 +11,7 @@ package org.zowe.apiml.util.http; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.methods.HttpGet; @@ -45,8 +46,7 @@ public static HttpResponse getResponse(String endpoint, int returnCode) throws I } public static HttpResponse getResponse(String endpoint, int returnCode, int port, String host) throws IOException { - HttpGet request = new HttpGet( - getUriFromGateway(endpoint, port, host, Collections.emptyList()) + HttpGet request = new HttpGet(getUriFromGateway(endpoint, port, host, Collections.emptyList()) ); // When @@ -64,6 +64,24 @@ public static HttpGet getRequest(String endpoint) { return new HttpGet(uri); } + public static URI getUriFromGateway(String scheme, String endpoint, int port, String host, NameValuePair... arguments) { + URI uri = null; + try { + uri = new URIBuilder() + .setScheme(scheme) + .setHost(host) + .setPort(port) + .setPath(endpoint) + .addParameters(Arrays.asList(arguments)) + .build(); + } catch (URISyntaxException e) { + log.error("Can't create URI for endpoint '{}'", endpoint); + e.printStackTrace(); + } + + return uri; + } + public static URI getUriFromGateway(String endpoint, int port, String host, List arguments) { GatewayServiceConfiguration gatewayServiceConfiguration = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration(); String scheme = gatewayServiceConfiguration.getScheme(); @@ -88,22 +106,20 @@ public static URI getUriFromGateway(String endpoint, int port, String host, List return uri; } - public static URI getUriFromGateway(String endpoint, List arguments) { - return getUriFromGateway(endpoint, ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getPort(), ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getHost(), arguments); + public static URI getUriFromGateway(GatewayServiceConfiguration serviceConfiguration, String endpoint, NameValuePair...arguments) { + String scheme = serviceConfiguration.getScheme(); + String host = serviceConfiguration.getHost(); + StringTokenizer hostnameTokenizer = new StringTokenizer(host, ","); + host = hostnameTokenizer.nextToken(); + if (StringUtils.isNotBlank(serviceConfiguration.getDvipaHost())) { + host = serviceConfiguration.getDvipaHost(); + } + int port = serviceConfiguration.getPort(); + return getUriFromGateway(scheme, endpoint, port, host, arguments); } - public static URI getUriFromGateway(String endpoint) { - return getUriFromGateway(endpoint, ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getPort(), ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getHost(), Collections.emptyList()); + public static URI getUriFromGateway(String endpoint, NameValuePair... arguments) { + return getUriFromGateway(ConfigReader.environmentConfiguration().getGatewayServiceConfiguration(), endpoint, arguments); } - public static URI getUriFromDiscovery(String endpoint, String host) throws URISyntaxException { - DiscoveryServiceConfiguration discoveryServiceConfiguration = ConfigReader.environmentConfiguration().getDiscoveryServiceConfiguration(); - - return new URIBuilder() - .setScheme(discoveryServiceConfiguration.getScheme()) - .setHost(host) - .setPort(discoveryServiceConfiguration.getPort()) - .setPath(endpoint) - .build(); - } } diff --git a/integration-tests/src/test/java/org/zowe/apiml/util/requests/ApiCatalogRequests.java b/integration-tests/src/test/java/org/zowe/apiml/util/requests/ApiCatalogRequests.java index 8d50b34609..e2668214d9 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/util/requests/ApiCatalogRequests.java +++ b/integration-tests/src/test/java/org/zowe/apiml/util/requests/ApiCatalogRequests.java @@ -10,9 +10,9 @@ package org.zowe.apiml.util.requests; -import com.jayway.jsonpath.ReadContext; import lombok.extern.slf4j.Slf4j; import org.apache.http.client.utils.URIBuilder; +import org.hamcrest.Matchers; import org.zowe.apiml.util.config.ApiCatalogServiceConfiguration; import org.zowe.apiml.util.config.ConfigReader; import org.zowe.apiml.util.config.Credentials; @@ -27,20 +27,19 @@ @Slf4j public class ApiCatalogRequests { - private static final ApiCatalogServiceConfiguration apiCatalogServiceConfiguration = ConfigReader.environmentConfiguration().getApiCatalogServiceConfiguration(); + private static final ApiCatalogServiceConfiguration apiCatalogServiceConfiguration = ConfigReader.environmentConfiguration().getApiCatalogServiceConfiguration(); private static final Credentials credentials = ConfigReader.environmentConfiguration().getCredentials(); - private final Requests requests; private final String scheme; private final String host; private final int port; private final String instance; public ApiCatalogRequests(String host) { - this(apiCatalogServiceConfiguration.getScheme(), host, apiCatalogServiceConfiguration.getPort(), new Requests()); + this(apiCatalogServiceConfiguration.getScheme(), host, apiCatalogServiceConfiguration.getPort()); } - public ApiCatalogRequests(String scheme, String host, int port, Requests requests) { - this.requests = requests; + + public ApiCatalogRequests(String scheme, String host, int port) { this.scheme = scheme; this.host = host; this.port = port; @@ -54,11 +53,17 @@ public boolean isUp() { try { log.info("ApiCatalogRequests#isUp Instance: {}", instance); - ReadContext healthResponse = requests.getJson(getApiCatalogUriWithPath("/apicatalog" + Endpoints.HEALTH)); - String health = healthResponse.read("$.status"); - - return health.equals("UP"); - } catch (Exception e) { + given() + .contentType(JSON) + .auth() + .basic(credentials.getUser(), credentials.getPassword()) + .when() + .get(getApiCatalogUriWithPath("/apicatalog" + Endpoints.HEALTH)) + .then() + .statusCode(200) + .body("status", Matchers.is("UP")); + return true; + } catch (AssertionError | URISyntaxException e) { log.info("ApiCatalogRequests#isUP", e); return false; @@ -71,7 +76,7 @@ public void shutdown() { try { given() .contentType(JSON) - .auth().basic(credentials.getUser(), new String(credentials.getPassword())) + .auth().basic(credentials.getUser(), credentials.getPassword()) .when() .post(getApiCatalogUriWithPath(Endpoints.SHUTDOWN)) .then() From 3a7fc09707fff195ff2b156317f5b725c21fb4b7 Mon Sep 17 00:00:00 2001 From: nx673747 Date: Thu, 27 Feb 2025 10:00:56 +0100 Subject: [PATCH 02/21] fix integration tests on zOS part 2 Signed-off-by: nx673747 --- .../common/auth/saf/SafResourceAccessSaf.java | 4 + .../auth/saf/SafResourceAccessSafTest.java | 9 +- .../AbstractIRRPassTicketException.java | 2 +- .../AbstractIRRPassTicketExceptionTest.java | 2 +- config/local/gateway-service.yml | 5 + .../src/main/resources/application.yml | 2 +- integration-tests/build.gradle | 68 +++++- .../ApiCatalogEndpointIntegrationTest.java | 66 ++++-- .../DiscoveryServiceAuthenticationTest.java | 46 ++-- .../gateway/GatewayAuthenticationTest.java | 18 +- .../pat/AccessTokenServiceTest.java | 209 +++++++++++++----- .../pat/PATWithAllSchemesTest.java | 41 ++-- .../authentication/providers/LogoutTest.java | 5 + .../authentication/providers/QueryTest.java | 40 ++-- .../providers/ZosmfLoginTest.java | 6 +- .../schemes/CloudGatewayAuthTest.java | 68 +++--- ...rviceProtectedEndpointIntegrationTest.java | 16 +- .../ha/ApiCatalogMultipleInstancesTest.java | 1 + .../integration/penetration/JwtPenTest.java | 3 +- .../integration/proxy/WebSocketProxyTest.java | 16 +- .../integration/zaas/PassTicketTest.java | 7 +- .../apiml/integration/zos/PassTicketTest.java | 54 +++-- .../integration/zos/ServicesInfoTest.java | 30 ++- .../util/categories/TestsNotMeantForZowe.java | 3 + .../zowe/apiml/util/config/ConfigReader.java | 33 ++- .../util/config/ConfigReaderZaasClient.java | 4 +- .../config/GatewayServiceConfiguration.java | 1 + .../config/ZosmfServiceConfiguration.java | 1 + keystore/README.md | 191 +++++++++------- keystore/client_cert/client-certs.p12 | Bin 7643 -> 8808 bytes onboarding-enabler-nodejs/.gitignore | 3 +- package.json | 2 +- 32 files changed, 641 insertions(+), 315 deletions(-) diff --git a/apiml-security-common/src/main/java/org/zowe/apiml/security/common/auth/saf/SafResourceAccessSaf.java b/apiml-security-common/src/main/java/org/zowe/apiml/security/common/auth/saf/SafResourceAccessSaf.java index 44b47d41eb..1f9116019f 100644 --- a/apiml-security-common/src/main/java/org/zowe/apiml/security/common/auth/saf/SafResourceAccessSaf.java +++ b/apiml-security-common/src/main/java/org/zowe/apiml/security/common/auth/saf/SafResourceAccessSaf.java @@ -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; @@ -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); diff --git a/apiml-security-common/src/test/java/org/zowe/apiml/security/common/auth/saf/SafResourceAccessSafTest.java b/apiml-security-common/src/test/java/org/zowe/apiml/security/common/auth/saf/SafResourceAccessSafTest.java index 00d8bb5530..ace8513b25 100644 --- a/apiml-security-common/src/test/java/org/zowe/apiml/security/common/auth/saf/SafResourceAccessSafTest.java +++ b/apiml-security-common/src/test/java/org/zowe/apiml/security/common/auth/saf/SafResourceAccessSafTest.java @@ -21,7 +21,9 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -88,6 +90,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 { diff --git a/common-service-core/src/main/java/org/zowe/apiml/passticket/AbstractIRRPassTicketException.java b/common-service-core/src/main/java/org/zowe/apiml/passticket/AbstractIRRPassTicketException.java index a7cc971bbd..6eab19d555 100644 --- a/common-service-core/src/main/java/org/zowe/apiml/passticket/AbstractIRRPassTicketException.java +++ b/common-service-core/src/main/java/org/zowe/apiml/passticket/AbstractIRRPassTicketException.java @@ -68,7 +68,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. " diff --git a/common-service-core/src/test/java/org/zowe/apiml/passticket/AbstractIRRPassTicketExceptionTest.java b/common-service-core/src/test/java/org/zowe/apiml/passticket/AbstractIRRPassTicketExceptionTest.java index 1a835292f8..45049d0127 100644 --- a/common-service-core/src/test/java/org/zowe/apiml/passticket/AbstractIRRPassTicketExceptionTest.java +++ b/common-service-core/src/test/java/org/zowe/apiml/passticket/AbstractIRRPassTicketExceptionTest.java @@ -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 { diff --git a/config/local/gateway-service.yml b/config/local/gateway-service.yml index 08effa38ec..28e36cbcf1 100644 --- a/config/local/gateway-service.yml +++ b/config/local/gateway-service.yml @@ -54,6 +54,11 @@ server: ssl: keyAlias: localhost-multi keyStore: keystore/localhost/localhost-multi.keystore.p12 + + webSocket: + requestBufferSize: 16348 + max-http-request-header-size: 16348 + ssl: keyAlias: localhost keyPassword: password diff --git a/gateway-service/src/main/resources/application.yml b/gateway-service/src/main/resources/application.yml index ffe653227d..9132949a63 100644 --- a/gateway-service/src/main/resources/application.yml +++ b/gateway-service/src/main/resources/application.yml @@ -225,7 +225,7 @@ management: web: base-path: /application exposure: - include: health,info,shutdown,hystrixstream + include: health,info,shutdown health: defaults: enabled: false diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle index 30000248d5..6bf20a20ab 100644 --- a/integration-tests/build.gradle +++ b/integration-tests/build.gradle @@ -78,7 +78,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 systemProperty "environment.offPlatform", true @@ -100,7 +100,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" @@ -176,14 +175,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 @@ -210,7 +209,58 @@ 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', + 'CloudGatewayProxyTest', + 'SafIdTokenTest', + 'ChaoticHATest', + 'GraphQLTest' + ) + } + + debugOptions { + port = 5005 + suspend = true + server = true + } + outputs.upToDateWhen { false } + outputs.cacheIf { false } } task runAllIntegrationTestsForZoweTesting(type: Test) { @@ -362,6 +412,7 @@ task runCloudGatewayProxyTest(type: Test) { ) } } + task runCloudGatewayServiceRoutingTest(type: Test) { group "integration tests" description "Run tests verifying cloud gateway can locate service and translate auth scheme" @@ -529,11 +580,14 @@ task runLbHaTests(type: Test) { task runChaoticHATests(type: Test) { group "Integration tests" description "Run Chaotic tests verifying High Availability" - dependsOn startUpCheck + + 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( diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/apicatalog/ApiCatalogEndpointIntegrationTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/apicatalog/ApiCatalogEndpointIntegrationTest.java index 3616e24507..5769226b52 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/apicatalog/ApiCatalogEndpointIntegrationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/apicatalog/ApiCatalogEndpointIntegrationTest.java @@ -20,7 +20,15 @@ import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpGet; import org.apache.http.util.EntityUtils; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.api.TestMethodOrder; import org.springframework.http.MediaType; import org.zowe.apiml.util.TestWithStartedInstances; import org.zowe.apiml.util.categories.CatalogTest; @@ -33,13 +41,22 @@ 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.Collectors; +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.junit.jupiter.api.Assertions.*; +import static org.hamcrest.Matchers.hasItem; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; import static org.zowe.apiml.util.SecurityUtils.COOKIE_NAME; @@ -47,7 +64,9 @@ 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"; @@ -55,19 +74,24 @@ class ApiCatalogEndpointIntegrationTest implements TestWithStartedInstances { 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 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 @@ -138,7 +162,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") + .collect(Collectors.toList()), hasItem(equalTo(swaggerServer))); assertNull(paths.get("/status/updates"), apiCatalogSwagger); assertNotNull(paths.get("/containers/{id}"), apiCatalogSwagger); assertNotNull(paths.get("/containers"), apiCatalogSwagger); @@ -171,7 +197,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") + .collect(Collectors.toList()), hasItem(equalTo(swaggerServer))); assertNull(paths.get("/status/updates"), apiCatalogSwagger); assertNotNull(paths.get("/containers/{id}"), apiCatalogSwagger); assertNotNull(paths.get("/containers"), apiCatalogSwagger); @@ -197,35 +225,37 @@ 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 { diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java index c31fa6a4f6..67b8d68787 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java @@ -14,11 +14,11 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.DisplayName; import org.zowe.apiml.util.SecurityUtils; import org.zowe.apiml.util.categories.GeneralAuthenticationTest; +import org.zowe.apiml.util.categories.TestsNotMeantForZowe; import org.zowe.apiml.util.config.ConfigReader; import org.zowe.apiml.util.config.ItSslConfigFactory; import org.zowe.apiml.util.config.SslContext; @@ -46,8 +46,10 @@ static void setup() throws Exception { @Nested class GivenBearerAuthentication { + @Nested class WhenAccessingProtectedEndpoint { + @Test void thenAuthenticate() { String token = SecurityUtils.gatewayToken(USERNAME, PASSWORD); @@ -58,13 +60,17 @@ void thenAuthenticate() { .then() .statusCode(is(SC_OK)); } + } + } @Nested class GivenInvalidBearerAuthentication { + @Nested class WhenAccessingProtectedEndpoint { + @Test void thenReturnUnauthorized() { String expectedMessage = "Token is not valid for URL '" + ACTUATOR_ENDPOINT + "'"; @@ -78,21 +84,33 @@ void thenReturnUnauthorized() { "messages.find { it.messageNumber == 'ZWEAS130E' }.messageContent", equalTo(expectedMessage) ); } + } + } - @Nested - @Tag("HealthEndpointProtectionDisabledTest") - class GivenHealthEndpointProtectionDisabled { - - @Test - @DisplayName("This test needs to run against discovery service instance that has application/health endpoint authentication disabled.") - void thenDoNotRequireAuthentication() { - given() - .when() - .get(DiscoveryUtils.getDiscoveryUrl() + DISCOVERY_HEALTH_ENDPOINT) - .then() - .statusCode(is(SC_OK)); - } + @Test + @TestsNotMeantForZowe("Automation needs unprotected health endpoint") + @DisplayName("This test needs to run against discovery service instance that has application/health endpoint authentication enabled.") + void thenDoNotRequireAuthentication() { + given() + .when() + .get(DiscoveryUtils.getDiscoveryUrl() + DISCOVERY_HEALTH_ENDPOINT) + .then() + .statusCode(is(SC_UNAUTHORIZED)); + + } + + @Test + @TestsNotMeantForZowe("Automation needs unprotected health endpoint") + @DisplayName("This test needs to run against discovery service instance that has application/health endpoint authentication enabled with authentication.") + void thenDoNotAuthenticateTheRequest() { + String token = SecurityUtils.gatewayToken(USERNAME, PASSWORD); + given() + .header("Authorization", "Bearer " + token) + .get(DiscoveryUtils.getDiscoveryUrl() + DISCOVERY_HEALTH_ENDPOINT) + .then() + .statusCode(is(SC_OK)); + } } diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java index 50600286c6..9646bfcc7b 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.params.provider.ValueSource; import org.zowe.apiml.util.SecurityUtils; import org.zowe.apiml.util.categories.GeneralAuthenticationTest; +import org.zowe.apiml.util.categories.TestsNotMeantForZowe; import org.zowe.apiml.util.config.ConfigReader; import org.zowe.apiml.util.http.HttpRequestUtils; @@ -30,6 +31,8 @@ class GatewayAuthenticationTest { private final static String PASSWORD = ConfigReader.environmentConfiguration().getCredentials().getPassword(); private final static String USERNAME = ConfigReader.environmentConfiguration().getCredentials().getUser(); + private static final String ACTUATOR_ENDPOINT = "/application"; + private static final String HEALTH_ENDPOINT = ACTUATOR_ENDPOINT + "/health"; @BeforeEach void setUp() { @@ -39,11 +42,12 @@ void setUp() { @Nested class GivenBearerAuthentication { + @Nested class WhenAccessingProtectedEndpoint { @ParameterizedTest - @ValueSource(strings = {"/application", "/application/health"}) + @ValueSource(strings = {ACTUATOR_ENDPOINT, HEALTH_ENDPOINT}) void thenAuthenticate(String endpoint) { String token = SecurityUtils.gatewayToken(USERNAME, PASSWORD); // Gateway request to url @@ -54,18 +58,22 @@ void thenAuthenticate(String endpoint) { .then() .statusCode(is(SC_OK)); } + } + } @Nested class GivenInvalidBearerAuthentication { + @Nested class WhenAccessingProtectedEndpoint { @ParameterizedTest - @ValueSource(strings = {"/application", "/application/health"}) + @TestsNotMeantForZowe("Automation needs unprotected health endpoint") + @ValueSource(strings = {ACTUATOR_ENDPOINT, HEALTH_ENDPOINT}) void thenReturnUnauthorized(String endpoint) { - String expectedMessage = "Token is not valid for URL '" + endpoint + "'"; + String expectedMessage = "The request has not been applied because it lacks valid authentication credentials."; // Gateway request to url given() .header("Authorization", "Bearer invalidToken") @@ -74,10 +82,12 @@ void thenReturnUnauthorized(String endpoint) { .then() .statusCode(is(SC_UNAUTHORIZED)) .body( - "messages.find { it.messageNumber == 'ZWEAG130E' }.messageContent", equalTo(expectedMessage) + "messages.find { it.messageNumber == 'ZWEAO402E' }.messageContent", equalTo(expectedMessage) ); } + } + } @Nested diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java index f91606383d..f8cc967ac6 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java @@ -14,6 +14,7 @@ import io.restassured.http.ContentType; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.zowe.apiml.util.SecurityUtils; @@ -28,6 +29,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.stream.IntStream; import static io.restassured.RestAssured.given; import static org.hamcrest.CoreMatchers.containsString; @@ -63,31 +65,56 @@ void setup() throws Exception { @Test void givenValidToken_invalidateTheToken() { - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .delete(REVOKE_ENDPOINT) - .then().statusCode(204); - given().contentType(ContentType.JSON).body(bodyContent).when() - .post(VALIDATE_ENDPOINT) - .then().statusCode(401); + .then() + .statusCode(204); + IntStream.range(0, 3).forEach(x -> { + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() + .post(VALIDATE_ENDPOINT) + .then() + .statusCode(401); + }); } + @Test void givenTokenInvalidated_returnUnauthorized() { - given().contentType(ContentType.JSON).body(bodyContent).when() - .delete(REVOKE_ENDPOINT) - .then().statusCode(204); - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .delete(REVOKE_ENDPOINT) - .then().statusCode(401); + .then() + .statusCode(204); + IntStream.range(0, 3).forEach(x -> { + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() + .delete(REVOKE_ENDPOINT) + .then() + .statusCode(401); + }); } @Test void givenMatchingScopes_validateTheToken() throws Exception { SslContext.prepareSslAuthentication(ItSslConfigFactory.integrationTests()); RestAssured.useRelaxedHTTPSValidation(); - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .post(VALIDATE_ENDPOINT) - .then().statusCode(204); + .then() + .statusCode(204); } @Test @@ -95,9 +122,13 @@ void givenInvalidScopes_returnUnauthorized() throws Exception { SslContext.prepareSslAuthentication(ItSslConfigFactory.integrationTests()); RestAssured.useRelaxedHTTPSValidation(); bodyContent.setServiceId("differentService"); - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .post(VALIDATE_ENDPOINT) - .then().statusCode(401); + .then() + .statusCode(401); } } @@ -120,19 +151,34 @@ void givenAuthorizedRequest_thenRevokeTokenForUser() { bodyContent.setServiceId("service"); bodyContent.setToken(pat); // validate before revocation rule - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .post(VALIDATE_ENDPOINT) - .then().statusCode(204); + .then() + .statusCode(204); // revoke all tokens for USERNAME Map requestBody = new HashMap<>(); requestBody.put("userId", SecurityUtils.USERNAME); - given().contentType(ContentType.JSON).config(SslContext.clientCertUser).body(requestBody) - .when().delete(REVOKE_FOR_USER_ENDPOINT) - .then().statusCode(204); + given() + .contentType(ContentType.JSON) + .config(SslContext.clientCertUser) + .body(requestBody) + .when() + .delete(REVOKE_FOR_USER_ENDPOINT) + .then() + .statusCode(204); // validate after revocation rule - given().contentType(ContentType.JSON).body(bodyContent).when() - .post(VALIDATE_ENDPOINT) - .then().statusCode(401); + IntStream.range(0, 3).forEach(x -> { + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() + .post(VALIDATE_ENDPOINT) + .then() + .statusCode(401); + }); } @Test @@ -142,17 +188,29 @@ void givenAuthenticatedCall_thenRevokeUserToken() { bodyContent.setServiceId("service"); bodyContent.setToken(pat); // validate before revocation rule - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .post(VALIDATE_ENDPOINT) - .then().statusCode(204); + .then() + .statusCode(204); // revoke all tokens for USERNAME - given().contentType(ContentType.JSON).config(SslContext.clientCertValid) - .when().delete(REVOKE_OWN_TOKENS_ENDPOINT) - .then().statusCode(204); + given() + .contentType(ContentType.JSON) + .config(SslContext.clientCertValid) + .when() + .delete(REVOKE_OWN_TOKENS_ENDPOINT) + .then() + .statusCode(204); // validate after revocation rule - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .post(VALIDATE_ENDPOINT) - .then().statusCode(401); + .then() + .statusCode(401); } @Test @@ -165,66 +223,107 @@ void givenAuthorizedRequest_thenRevokeTokensForScope() { bodyContent.setServiceId("gateway"); bodyContent.setToken(pat); // validate before revocation rule - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .post(VALIDATE_ENDPOINT) - .then().statusCode(204); + .then() + .statusCode(204); // revoke all tokens for USERNAME Map requestBody = new HashMap<>(); requestBody.put("serviceId", "api-catalog"); - given().contentType(ContentType.JSON).config(SslContext.clientCertUser).body(requestBody) - .when().delete(REVOKE_FOR_SCOPE_ENDPOINT) - .then().statusCode(204); + given() + .contentType(ContentType.JSON) + .config(SslContext.clientCertUser) + .body(requestBody) + .when() + .delete(REVOKE_FOR_SCOPE_ENDPOINT) + .then() + .statusCode(204); // validate after revocation rule - given().contentType(ContentType.JSON).body(bodyContent).when() - .post(VALIDATE_ENDPOINT) - .then().statusCode(401); + IntStream.range(0, 3).forEach(x -> { + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() + .post(VALIDATE_ENDPOINT) + .then() + .statusCode(401); + }); } + @Test void givenAuthorizedRequest_thenEvictRules() { // add rule with timestamp older than 90 days, meaning it is not relevant anymore Map requestBody = new HashMap<>(); requestBody.put("userId", SecurityUtils.USERNAME); requestBody.put("timestamp", "1582239600000"); - given().contentType(ContentType.JSON).config(SslContext.clientCertUser).body(requestBody) - .when().delete(REVOKE_FOR_USER_ENDPOINT) - .then().statusCode(204); + given() + .contentType(ContentType.JSON) + .config(SslContext.clientCertUser) + .body(requestBody) + .when() + .delete(REVOKE_FOR_USER_ENDPOINT) + .then() + .statusCode(204); // evict the rule - given().contentType(ContentType.JSON).config(SslContext.clientCertUser) + given() + .contentType(ContentType.JSON) + .config(SslContext.clientCertUser) .when() .delete(EVICT_ENDPOINT) - .then().statusCode(204); + .then() + .statusCode(204); // return all the items from the cache - given().contentType(ContentType.JSON).config(SslContext.clientCertUser) + given() + .contentType(ContentType.JSON) + .config(SslContext.clientCertUser) .when() .get(CACHE_LIST_ENDPOINT) .then() .statusCode(200) - .body("content", not(containsString("1582239600000"))).extract().asString(); + .body("content", not(containsString("1582239600000"))) + .extract() + .asString(); } @Test + @Disabled("Disable for now; fix is in progress") void givenNotAuthorizedCall_thenDontAllowToRevokeTokensForUser() { String pat = SecurityUtils.personalAccessTokenWithClientCert(SslContext.clientCertValid); bodyContent = new ValidateRequestModel(); bodyContent.setServiceId("service"); bodyContent.setToken(pat); // validate before revocation rule - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .post(VALIDATE_ENDPOINT) - .then().statusCode(204); -// revoke all tokens for USERNAME - Map requestBody = new HashMap<>(); - requestBody.put("userId", SecurityUtils.USERNAME); - given().contentType(ContentType.JSON).config(SslContext.clientCertApiml).body(requestBody) - .when().delete(REVOKE_FOR_USER_ENDPOINT) - .then().statusCode(403); + .then() + .statusCode(204); // validate after revocation rule - given().contentType(ContentType.JSON).body(bodyContent).when() + given() + .contentType(ContentType.JSON) + .body(bodyContent) + .when() .post(VALIDATE_ENDPOINT) - .then().statusCode(204); + .then() + .statusCode(204); + // revoke all tokens for USERNAME + Map requestBody = new HashMap<>(); + requestBody.put("userId", SecurityUtils.USERNAME); + given() + .contentType(ContentType.JSON) + .config(SslContext.clientCertApiml) + .body(requestBody) + .when() + .delete(REVOKE_FOR_USER_ENDPOINT) + .then() + .statusCode(403); } } - } diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java index 2c98e7893a..ba038ffec0 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java @@ -22,13 +22,17 @@ import org.junit.jupiter.params.provider.MethodSource; import org.zowe.apiml.constants.ApimlConstants; import org.zowe.apiml.util.categories.InfinispanStorageTest; +import org.zowe.apiml.util.config.ConfigReader; import org.zowe.apiml.util.config.ItSslConfigFactory; +import org.zowe.apiml.util.config.SafIdtConfiguration; import org.zowe.apiml.util.config.SslContext; import org.zowe.apiml.util.http.HttpRequestUtils; import java.net.URI; import java.text.ParseException; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.stream.Stream; @@ -42,7 +46,9 @@ import static org.zowe.apiml.util.SecurityUtils.personalAccessToken; import static org.zowe.apiml.util.requests.Endpoints.*; - class PATWithAllSchemesTest { +class PATWithAllSchemesTest { + + private static final SafIdtConfiguration safIdtConfig = ConfigReader.environmentConfiguration().getSafIdtConfiguration(); static Stream authentication() { return Stream.of( @@ -54,28 +60,32 @@ static Stream authentication() { } static Stream schemas() { - return Stream.of( + List schemasTest = new ArrayList<>(); + schemasTest.add( Arguments.of("zowejwt", HttpRequestUtils.getUriFromGateway(ZOWE_JWT_REQUEST), (Consumer) r -> { - assertEquals(HttpStatus.SC_OK, r.getStatusCode() ); + assertEquals(HttpStatus.SC_OK, r.getStatusCode()); assertThat(r.getBody().path("headers.cookie"), containsString(COOKIE_NAME)); String jwt = r.getBody().path("headers.authorization").toString(); try { - String issuer = JWTParser.parse(jwt.substring(ApimlConstants.BEARER_AUTHENTICATION_PREFIX.length()).trim()).getJWTClaimsSet().toJSONObject().get("iss").toString(); + String issuer = JWTParser.parse(jwt.substring(ApimlConstants.BEARER_AUTHENTICATION_PREFIX.length()).trim()).getJWTClaimsSet().toJSONObject().get("iss").toString(); assertEquals("APIML", issuer); } catch (ParseException e) { fail(e); } - }), + })); + schemasTest.add( Arguments.of("dcpassticket", HttpRequestUtils.getUriFromGateway(REQUEST_INFO_ENDPOINT), (Consumer) r -> { - assertEquals(HttpStatus.SC_OK, r.getStatusCode() ); + assertEquals(HttpStatus.SC_OK, r.getStatusCode()); assertThat(r.getBody().path("headers.authorization"), startsWith("Basic ")); assertThat(r.getBody().path("cookies"), not(hasKey(COOKIE_NAME))); - }), + })); + if (safIdtConfig.isEnabled()) { Arguments.of("dcsafidt", HttpRequestUtils.getUriFromGateway(SAF_IDT_REQUEST), (Consumer) r -> { - assertEquals(HttpStatus.SC_OK, r.getStatusCode() ); + assertEquals(HttpStatus.SC_OK, r.getStatusCode()); assertThat(r.getBody().path("headers"), hasKey("x-saf-token")); - }) - ); + }); + } + return schemasTest.stream(); } static Stream authSchemas() { @@ -97,10 +107,13 @@ void requestWithPAT( String name, URI urlSpecification, Consumer validation) { String pat = personalAccessToken(Collections.singleton(name)); - validation.accept(authenticationAction.apply(given(), pat) + Response response = authenticationAction.apply(given(), pat) .config(SslContext.tlsWithoutCert) - .when() - .get(urlSpecification) - ); + .when() + .get(urlSpecification); + + assertEquals(HttpStatus.SC_OK, response.getStatusCode(), "Expected HTTP 200 OK response"); + + validation.accept(response); } } diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/LogoutTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/LogoutTest.java index 22fa3e48a3..b8b23922ad 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/LogoutTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/LogoutTest.java @@ -46,8 +46,10 @@ void setUp() { @Nested class WhenUserLogOut { + @Nested class InvalidateTheToken { + @ParameterizedTest(name = "givenValidCredentials {index} {0} ") @MethodSource("org.zowe.apiml.integration.authentication.providers.LogoutTest#logoutUrlsSource") void givenValidCredentials(String logoutUrl) { @@ -62,6 +64,9 @@ void givenValidCredentials(String logoutUrl) { // check if it is logged out assertIfLogged(jwt, false); } + } + } + } diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/QueryTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/QueryTest.java index 417e841e3c..426db98bf7 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/QueryTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/QueryTest.java @@ -12,8 +12,10 @@ import io.restassured.RestAssured; import org.apache.commons.lang3.StringUtils; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.zowe.apiml.util.SecurityUtils; @@ -36,33 +38,33 @@ @GeneralAuthenticationTest @SAFAuthTest @zOSMFAuthTest +@TestInstance(Lifecycle.PER_CLASS) class QueryTest implements TestWithStartedInstances { - private final static String SCHEME = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getScheme(); - private final static String HOST = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getHost(); - private final static int PORT = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getPort(); - private final static String BASE_PATH = "/gateway/api/v1"; - private final static String BASE_PATH_OLD_FORMAT = "/api/v1/gateway"; - private final static String QUERY_ENDPOINT = "/auth/query"; - private final static String PASSWORD = ConfigReader.environmentConfiguration().getCredentials().getPassword(); - private final static String USERNAME = ConfigReader.environmentConfiguration().getCredentials().getUser(); - private final static String COOKIE = "apimlAuthenticationToken"; + private static final String SCHEME = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getScheme(); + private static final String HOST = StringUtils.isBlank(ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getDvipaHost()) ? ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getHost() : ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getDvipaHost(); + private static final int PORT = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration().getPort(); + private static final String BASE_PATH = "/gateway/api/v1"; + private static final String BASE_PATH_OLD_FORMAT = "/api/v1/gateway"; + private static final String QUERY_ENDPOINT = "/auth/query"; + private static final String PASSWORD = ConfigReader.environmentConfiguration().getCredentials().getPassword(); + private static final String USERNAME = ConfigReader.environmentConfiguration().getCredentials().getUser(); + private static final String COOKIE = "apimlAuthenticationToken"; public static final String QUERY_ENDPOINT_URL = String.format("%s://%s:%d%s%s", SCHEME, HOST, PORT, BASE_PATH, QUERY_ENDPOINT); public static final String QUERY_ENDPOINT_URL_OLD_FORMAT = String.format("%s://%s:%d%s%s", SCHEME, HOST, PORT, BASE_PATH_OLD_FORMAT, QUERY_ENDPOINT); - private String token; + private String validToken; static String[] queryUrlsSource() { return new String[]{QUERY_ENDPOINT_URL, QUERY_ENDPOINT_URL_OLD_FORMAT}; } - @BeforeEach - void setUp() { + @BeforeAll + void init() { + this.validToken = SecurityUtils.gatewayToken(USERNAME, PASSWORD); RestAssured.port = PORT; RestAssured.basePath = BASE_PATH; RestAssured.useRelaxedHTTPSValidation(); - - token = SecurityUtils.gatewayToken(USERNAME, PASSWORD); } @Nested @@ -74,7 +76,7 @@ class ReturnInfo { @MethodSource("org.zowe.apiml.integration.authentication.providers.QueryTest#queryUrlsSource") void givenValidTokenInHeader(String queryUrl) { given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + validToken) .when() .get(queryUrl) .then() @@ -86,7 +88,7 @@ void givenValidTokenInHeader(String queryUrl) { @MethodSource("org.zowe.apiml.integration.authentication.providers.QueryTest#queryUrlsSource") void givenValidTokenInCookie(String queryUrl) { given() - .cookie(COOKIE, token) + .cookie(COOKIE, validToken) .when() .get(queryUrl) .then() @@ -158,7 +160,7 @@ void givenValidTokenInWrongCookie(String queryUrl) { String expectedMessage = "No authorization token provided for URL '" + queryPath + "'"; given() - .cookie(invalidCookie, token) + .cookie(invalidCookie, validToken) .when() .get(queryUrl) .then() @@ -181,7 +183,7 @@ void givenValidToken(String queryUrl) { String expectedMessage = "Authentication method 'POST' is not supported for URL '" + queryPath + "'"; given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + validToken) .when() .post(queryUrl) .then() diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/ZosmfLoginTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/ZosmfLoginTest.java index f8e855bf24..75934f0ad2 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/ZosmfLoginTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/ZosmfLoginTest.java @@ -19,6 +19,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.util.StringUtils; import org.zowe.apiml.util.TestWithStartedInstances; import org.zowe.apiml.util.categories.zOSMFAuthTest; import org.zowe.apiml.util.config.ConfigReader; @@ -46,9 +47,10 @@ class ZosmfLoginTest implements TestWithStartedInstances { private final static boolean ZOS_TARGET = Boolean.parseBoolean(System.getProperty("environment.zos.target", "false")); private final static String ZOSMF_SERVICE_ID = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getServiceId(); + private static final String ZOSMF_CONTEXT_ROOT = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getContextRoot(); + private final static String ZOSMF_ENDPOINT_GW = "/" + ZOSMF_SERVICE_ID + "/api/v1/" + (StringUtils.hasText(ZOSMF_CONTEXT_ROOT) ? ZOSMF_CONTEXT_ROOT + "/" : "") + "restfiles/ds"; private final static String USERNAME = ConfigReader.environmentConfiguration().getCredentials().getClientUser(); private final static String ZOSMF_ENDPOINT_MOCK = "/" + ZOSMF_SERVICE_ID + "/api/zosmf/restfiles/ds"; - private final static String ZOSMF_ENDPOINT_GW = "/" + ZOSMF_SERVICE_ID + "/api/v1/restfiles/ds"; private final static String ZOSMF_ENDPOINT = ZOS_TARGET ? ZOSMF_ENDPOINT_GW : ZOSMF_ENDPOINT_MOCK; @BeforeAll @@ -71,7 +73,7 @@ void givenValidCertificate_thenReturnExistingDatasets() { arguments.add(new BasicNameValuePair("dslevel", "sys1.p*")); given() - .config(SslContext.clientCertValid) + .config(SslContext.clientCertUser) .header("X-CSRF-ZOSMF-HEADER", "") .when() .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/CloudGatewayAuthTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/CloudGatewayAuthTest.java index 34d56e1925..b6bf14fb04 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/CloudGatewayAuthTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/CloudGatewayAuthTest.java @@ -52,28 +52,28 @@ @ZaasTest public class CloudGatewayAuthTest implements TestWithStartedInstances { - private static final CloudGatewayConfiguration GATEWAY_CONFIGURATION = ConfigReader.environmentConfiguration().getCloudGatewayConfiguration(); - private static final SafIdtConfiguration SAF_IDT_CONFIGURATION = ConfigReader.environmentConfiguration().getSafIdtConfiguration(); + private static final CloudGatewayConfiguration CLOUD_GATEWAY_CONFIGURATION = ConfigReader.environmentConfiguration().getCloudGatewayConfiguration(); + private static final SafIdtConfiguration SAF_IDT_CONF = ConfigReader.environmentConfiguration().getSafIdtConfiguration(); static Stream validToBeTransformed() { List arguments = new ArrayList<>(Arrays.asList( Arguments.of("Zowe auth scheme", ZOWE_JWT_REQUEST, (Consumer) response -> { - assertNotNull(response.jsonPath().getString("cookies.apimlAuthenticationToken")); - assertNull(response.jsonPath().getString("headers.authorization")); - assertTrue(CollectionUtils.isEmpty(response.jsonPath().getList("certs"))); + assertNotNull(response.jsonPath().getString("cookies.apimlAuthenticationToken"), "Expected not null apimlAuthenticationToken. Response was: " + response.asPrettyString()); + assertNull(response.jsonPath().getString("headers.authorization"), "Expected null Authorization header. Response was: " + response.asPrettyString()); + assertTrue(CollectionUtils.isEmpty(response.jsonPath().getList("certs")), "Expected empty certs list. Response was: " + response.asPrettyString()); }), Arguments.of("z/OSMF auth scheme", ZOSMF_REQUEST, (Consumer) response -> { - assertNotNull(response.jsonPath().getString("cookies.jwtToken")); - assertNull(response.jsonPath().getString("headers.authorization")); - assertTrue(CollectionUtils.isEmpty(response.jsonPath().getList("certs"))); + assertNotNull(response.jsonPath().getString("cookies.jwtToken"), "Expected not null jwtToken cookie. Response was: " + response.asPrettyString()); + assertNull(response.jsonPath().getString("headers.authorization"), "Expected null Authorization header. Response was: " + response.asPrettyString()); + assertTrue(CollectionUtils.isEmpty(response.jsonPath().getList("certs")), "Expected empty certs list. Response was: " + response.asPrettyString()); }), Arguments.of("PassTicket auth scheme", REQUEST_INFO_ENDPOINT, (Consumer) response -> { - assertNotNull(response.jsonPath().getString("headers.authorization")); - assertTrue(response.jsonPath().getString("headers.authorization").startsWith("Basic ")); + assertNotNull(response.jsonPath().getString("headers.authorization"), "Expected not null Authorization header. Response was: " + response.asPrettyString()); + assertTrue(response.jsonPath().getString("headers.authorization").startsWith("Basic "), "Expected basic Authorization present. Response was: " + response.asPrettyString()); assertTrue(CollectionUtils.isEmpty(response.jsonPath().getList("certs"))); }) )); - if (SAF_IDT_CONFIGURATION.isEnabled()) { + if (SAF_IDT_CONF.isEnabled()) { arguments.add(Arguments.of("SAF IDT auth scheme", SAF_IDT_REQUEST, (Consumer) response -> { assertNull(response.jsonPath().getString("cookies.jwtToken")); assertNotNull(response.jsonPath().getString("headers.x-saf-token")); @@ -86,10 +86,10 @@ static Stream validToBeTransformed() { static Stream noAuthTransformation() { Consumer assertions = response -> { assertEquals(200, response.getStatusCode()); - assertNull(response.jsonPath().getString("cookies.apimlAuthenticationToken")); - assertNull(response.jsonPath().getString("cookies.jwtToken")); - assertNull(response.jsonPath().getString("headers.authorization")); - assertTrue(CollectionUtils.isEmpty(response.jsonPath().getList("certs"))); + assertNull(response.jsonPath().getString("cookies.apimlAuthenticationToken"), "Expected cookies.apimlAuthenticationToken to be Null. Response is: " + response.asPrettyString()); + assertNull(response.jsonPath().getString("cookies.jwtToken"), "Expected cookies.jwtToken to be Null. Response is: " + response.asPrettyString()); + assertNull(response.jsonPath().getString("headers.authorization"), "Expected headers.authorization to be Null. Response is: " + response.asPrettyString()); + assertTrue(CollectionUtils.isEmpty(response.jsonPath().getList("certs")), "Expected empty certs. Response is: " + response.asPrettyString()); }; List arguments = new ArrayList<>(Arrays.asList( @@ -97,7 +97,7 @@ static Stream noAuthTransformation() { Arguments.of("z/OSMF auth scheme", ZOSMF_REQUEST, assertions), Arguments.of("PassTicket auth scheme", REQUEST_INFO_ENDPOINT, assertions) )); - if (SAF_IDT_CONFIGURATION.isEnabled()) { + if (SAF_IDT_CONF.isEnabled()) { arguments.add(Arguments.of("SAF IDT auth scheme", SAF_IDT_REQUEST, assertions)); } return arguments.stream(); @@ -122,8 +122,8 @@ void givenValidRequest_thenCredentialsAreTransformed(String title, String basePa Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + gatewayToken) - .when() - .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); + .when() + .get(String.format("%s://%s:%s%s", CLOUD_GATEWAY_CONFIGURATION.getScheme(), CLOUD_GATEWAY_CONFIGURATION.getHost(), CLOUD_GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -136,8 +136,8 @@ void givenValidRequest_thenPatIsTransformed(String title, String basePath, Consu Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + pat) - .when() - .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); + .when() + .get(String.format("%s://%s:%s%s", CLOUD_GATEWAY_CONFIGURATION.getScheme(), CLOUD_GATEWAY_CONFIGURATION.getHost(), CLOUD_GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -147,8 +147,8 @@ void givenValidRequest_thenPatIsTransformed(String title, String basePath, Consu void givenValidRequest_thenClientCertIsTransformed(String title, String basePath, Consumer assertions) { Response response = given() .config(SslContext.clientCertValid) - .when() - .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); + .when() + .get(String.format("%s://%s:%s%s", CLOUD_GATEWAY_CONFIGURATION.getScheme(), CLOUD_GATEWAY_CONFIGURATION.getHost(), CLOUD_GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -160,8 +160,8 @@ void givenValidRequest_thenOidcIsTransformed(String title, String basePath, Cons Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + oAuthToken) - .when() - .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); + .when() + .get(String.format("%s://%s:%s%s", CLOUD_GATEWAY_CONFIGURATION.getScheme(), CLOUD_GATEWAY_CONFIGURATION.getHost(), CLOUD_GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -178,10 +178,10 @@ void givenInvalidPatRequest_thenPatIsNotTransformed(String title, String basePat Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + pat) - .when() - .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); + .when() + .get(String.format("%s://%s:%s%s", CLOUD_GATEWAY_CONFIGURATION.getScheme(), CLOUD_GATEWAY_CONFIGURATION.getHost(), CLOUD_GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); - assertEquals(200, response.getStatusCode()); + assertEquals(200, response.getStatusCode(), "Expected 200 while using token " + pat); } @ParameterizedTest(name = "givenInvalidRequest_thenClientCertIsNotTransformed {0} [{index}]") @@ -189,8 +189,8 @@ void givenInvalidPatRequest_thenPatIsNotTransformed(String title, String basePat void givenInvalidRequest_thenClientCertIsNotTransformed(String title, String basePath, Consumer assertions) { Response response = given() .config(SslContext.selfSignedUntrusted) - .when() - .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); + .when() + .get(String.format("%s://%s:%s%s", CLOUD_GATEWAY_CONFIGURATION.getScheme(), CLOUD_GATEWAY_CONFIGURATION.getHost(), CLOUD_GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -202,8 +202,8 @@ void givenInvalidRequest_thenOidcIsNotTransformed(String title, String basePath, Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer " + oAuthToken) - .when() - .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); + .when() + .get(String.format("%s://%s:%s%s", CLOUD_GATEWAY_CONFIGURATION.getScheme(), CLOUD_GATEWAY_CONFIGURATION.getHost(), CLOUD_GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -212,7 +212,7 @@ void givenInvalidRequest_thenOidcIsNotTransformed(String title, String basePath, @MethodSource("org.zowe.apiml.integration.authentication.schemes.CloudGatewayAuthTest#noAuthTransformation") void givenNoCredentials_thenNoCredentialsAreProvided(String title, String basePath, Consumer assertions) { Response response = when() - .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); + .get(String.format("%s://%s:%s%s", CLOUD_GATEWAY_CONFIGURATION.getScheme(), CLOUD_GATEWAY_CONFIGURATION.getHost(), CLOUD_GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } @@ -222,8 +222,8 @@ void givenNoCredentials_thenNoCredentialsAreProvided(String title, String basePa void givenInvalidCredentials_thenNoCredentialsAreProvided(String title, String basePath, Consumer assertions) { Response response = given() .header(HttpHeaders.AUTHORIZATION, "Bearer invalidToken") - .when() - .get(String.format("%s://%s:%s%s", GATEWAY_CONFIGURATION.getScheme(), GATEWAY_CONFIGURATION.getHost(), GATEWAY_CONFIGURATION.getPort(), basePath)); + .when() + .get(String.format("%s://%s:%s%s", CLOUD_GATEWAY_CONFIGURATION.getScheme(), CLOUD_GATEWAY_CONFIGURATION.getHost(), CLOUD_GATEWAY_CONFIGURATION.getPort(), basePath)); assertions.accept(response); assertEquals(200, response.getStatusCode()); } diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/services/ServiceProtectedEndpointIntegrationTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/services/ServiceProtectedEndpointIntegrationTest.java index a18a24d5a6..ae6c66cc10 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/services/ServiceProtectedEndpointIntegrationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/services/ServiceProtectedEndpointIntegrationTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.springframework.util.StringUtils; import org.zowe.apiml.util.SecurityUtils; import org.zowe.apiml.util.TestWithStartedInstances; import org.zowe.apiml.util.categories.zOSMFAuthTest; @@ -40,15 +41,16 @@ @zOSMFAuthTest class ServiceProtectedEndpointIntegrationTest implements TestWithStartedInstances { - private final static boolean ZOS_TARGET = Boolean.parseBoolean(System.getProperty("environment.zos.target", "false")); - private final static String PASSWORD = ConfigReader.environmentConfiguration().getCredentials().getPassword(); - private final static String USERNAME = ConfigReader.environmentConfiguration().getCredentials().getUser(); + private static final boolean ZOS_TARGET = Boolean.parseBoolean(System.getProperty("environment.zos.target", "false")); + private static final String PASSWORD = ConfigReader.environmentConfiguration().getCredentials().getPassword(); + private static final String USERNAME = ConfigReader.environmentConfiguration().getCredentials().getUser(); - private final static String ZOSMF_SERVICE_ID = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getServiceId(); + private static final String ZOSMF_SERVICE_ID = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getServiceId(); + private static final String ZOSMF_CONTEXT_ROOT = ConfigReader.environmentConfiguration().getZosmfServiceConfiguration().getContextRoot(); - private final static String ZOSMF_ENDPOINT_MOCK = "/" + ZOSMF_SERVICE_ID + "/api/zosmf/restfiles/ds"; - private final static String ZOSMF_ENDPOINT_GW = "/" + ZOSMF_SERVICE_ID + "/api/v1/restfiles/ds"; - private final static String ZOSMF_ENDPOINT = ZOS_TARGET ? ZOSMF_ENDPOINT_GW : ZOSMF_ENDPOINT_MOCK; + private static final String ZOSMF_ENDPOINT_MOCK = "/" + ZOSMF_SERVICE_ID + "/api/zosmf/restfiles/ds"; + private static final String ZOSMF_ENDPOINT_GW = "/" + ZOSMF_SERVICE_ID + "/api/v1/" + (StringUtils.hasText(ZOSMF_CONTEXT_ROOT) ? ZOSMF_CONTEXT_ROOT + "/" : "") + "restfiles/ds"; + private static final String ZOSMF_ENDPOINT = ZOS_TARGET ? ZOSMF_ENDPOINT_GW : ZOSMF_ENDPOINT_MOCK; private List arguments; diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/ha/ApiCatalogMultipleInstancesTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/ha/ApiCatalogMultipleInstancesTest.java index 451fc97aed..8f96f644c8 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/ha/ApiCatalogMultipleInstancesTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/ha/ApiCatalogMultipleInstancesTest.java @@ -31,6 +31,7 @@ public class ApiCatalogMultipleInstancesTest { private final HAApiCatalogRequests haApiCatalogRequests = new HAApiCatalogRequests(); private final HADiscoveryRequests haDiscoveryRequests = new HADiscoveryRequests(); + @BeforeEach void setUp() { RestAssured.config = RestAssured.config().sslConfig(getConfiguredSslConfig().relaxedHTTPSValidation()); diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/penetration/JwtPenTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/penetration/JwtPenTest.java index 3c8b13ff5d..d36b6bd31f 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/penetration/JwtPenTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/penetration/JwtPenTest.java @@ -14,6 +14,7 @@ import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import io.restassured.RestAssured; +import org.apache.commons.lang3.StringUtils; import org.json.JSONObject; import org.junit.jupiter.api.Nested; import org.junit.jupiter.params.ParameterizedTest; @@ -70,7 +71,7 @@ public class JwtPenTest implements TestWithStartedInstances { private static final EnvironmentConfiguration ENV = ConfigReader.environmentConfiguration(); private static final String SCHEME = ENV.getGatewayServiceConfiguration().getScheme(); - private static final String HOST = ENV.getGatewayServiceConfiguration().getHost(); + private static final String HOST = StringUtils.isNotBlank(ENV.getGatewayServiceConfiguration().getDvipaHost()) ? ENV.getGatewayServiceConfiguration().getDvipaHost() : ENV.getGatewayServiceConfiguration().getHost(); private static final int PORT = ENV.getGatewayServiceConfiguration().getPort(); private static final String APPLICATION_NAME = ENV.getDiscoverableClientConfiguration().getApplId(); private static final String USERNAME = ENV.getCredentials().getUser(); diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/proxy/WebSocketProxyTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/proxy/WebSocketProxyTest.java index 2dcb656823..a7226eacb7 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/proxy/WebSocketProxyTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/proxy/WebSocketProxyTest.java @@ -11,7 +11,9 @@ package org.zowe.apiml.integration.proxy; import io.restassured.RestAssured; +import org.apache.commons.lang3.StringUtils; import org.apache.http.client.utils.URIBuilder; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -49,7 +51,7 @@ @TestsNotMeantForZowe @WebsocketTest class WebSocketProxyTest implements TestWithStartedInstances { - private final GatewayServiceConfiguration serviceConfiguration = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration(); + private final GatewayServiceConfiguration gatewayConfiguration = ConfigReader.environmentConfiguration().getGatewayServiceConfiguration(); private static final URI DC_WS_REST_ENDPOINT = HttpRequestUtils.getUriFromGateway("/discoverableclient/api/v1/ws"); private static final int WAIT_TIMEOUT_MS = 10000; @@ -72,6 +74,12 @@ void setup() { } + @AfterAll + static void teardown() { + VALID_AUTH_HEADERS.clear(); + INVALID_AUTH_HEADERS.clear(); + } + private TextWebSocketHandler appendResponseHandler(StringBuilder target, int countToNotify) { final AtomicInteger counter = new AtomicInteger(countToNotify); return new TextWebSocketHandler() { @@ -100,9 +108,9 @@ public void afterConnectionClosed(WebSocketSession session, CloseStatus status) } private String discoverableClientGatewayUrl(String gatewayUrl) throws URISyntaxException { - String scheme = serviceConfiguration.getScheme().equals("http") ? "ws" : "wss"; - String host = serviceConfiguration.getHost(); - int port = serviceConfiguration.getPort(); + String scheme = gatewayConfiguration.getScheme().equals("http") ? "ws" : "wss"; + String host = StringUtils.isNotBlank(gatewayConfiguration.getDvipaHost()) ? gatewayConfiguration.getDvipaHost() : gatewayConfiguration.getHost(); + int port = gatewayConfiguration.getPort(); return new URIBuilder().setScheme(scheme).setHost(host).setPort(port).setPath(gatewayUrl).build().toString(); } diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/PassTicketTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/PassTicketTest.java index 8fbed4f025..6dd40142e1 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/PassTicketTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/PassTicketTest.java @@ -32,7 +32,7 @@ import static io.restassured.RestAssured.given; import static io.restassured.http.ContentType.JSON; -import static io.restassured.http.ContentType.XML; +import static io.restassured.http.ContentType.TEXT; import static org.apache.http.HttpStatus.SC_BAD_REQUEST; import static org.apache.http.HttpStatus.SC_NOT_FOUND; import static org.apache.http.HttpStatus.SC_OK; @@ -41,6 +41,7 @@ import static org.hamcrest.Matchers.isEmptyOrNullString; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase; import static org.zowe.apiml.integration.zaas.ZaasTestUtil.COOKIE; import static org.zowe.apiml.integration.zaas.ZaasTestUtil.ZAAS_TICKET_URI; import static org.zowe.apiml.util.SecurityUtils.USERNAME; @@ -161,7 +162,7 @@ void givenValidOAuthToken() { .then() .statusCode(SC_OK) .body("ticket", not(isEmptyOrNullString())) - .body("userId", is(USERNAME)) + .body("userId", equalToIgnoringCase(USERNAME)) .body("applicationName", is(APPLICATION_NAME)); //@formatter:on } @@ -241,7 +242,7 @@ void givenInvalidContentType() { given() .body(new TicketRequest(APPLICATION_NAME)) .cookie(COOKIE, jwt) - .contentType(XML) + .contentType(TEXT) .when() .post(ZAAS_TICKET_URI) .then() diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/zos/PassTicketTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/zos/PassTicketTest.java index df3aeea95e..80ec4d6311 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/zos/PassTicketTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/zos/PassTicketTest.java @@ -28,14 +28,20 @@ import static io.restassured.RestAssured.given; import static io.restassured.http.ContentType.JSON; -import static org.apache.http.HttpStatus.*; +import static org.apache.http.HttpStatus.SC_BAD_REQUEST; +import static org.apache.http.HttpStatus.SC_FORBIDDEN; +import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.apache.http.HttpStatus.SC_METHOD_NOT_ALLOWED; +import static org.apache.http.HttpStatus.SC_OK; +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; +import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.zowe.apiml.passticket.PassTicketService.DefaultPassTicketImpl.UNKNOWN_APPLID; import static org.zowe.apiml.util.SecurityUtils.gatewayToken; import static org.zowe.apiml.util.SecurityUtils.getConfiguredSslConfig; -import static org.zowe.apiml.util.requests.Endpoints.*; +import static org.zowe.apiml.util.requests.Endpoints.ROUTED_PASSTICKET; /** * Verify integration of the API ML Passticket support with the zOS provider of the Passticket. @@ -52,7 +58,7 @@ class PassTicketTest implements TestWithStartedInstances { private final static String APPLICATION_NAME = DISCOVERABLE_CLIENT_CONFIGURATION.getApplId(); private final static String COOKIE = "apimlAuthenticationToken"; - private URI url = HttpRequestUtils.getUriFromGateway(ROUTED_PASSTICKET); + private final URI url = HttpRequestUtils.getUriFromGateway(ROUTED_PASSTICKET); @BeforeEach void setUp() { @@ -84,9 +90,9 @@ void givenValidTokenInCookieAndCertificate() { .contentType(JSON) .body(ticketRequest) .cookie(COOKIE, jwt) - .when() + .when() .post(url) - .then() + .then() .statusCode(is(SC_OK)) .extract().body().as(TicketResponse.class); @@ -99,9 +105,9 @@ void givenValidTokenInHeaderAndCertificate() { .contentType(JSON) .body(ticketRequest) .header("Authorization", "Bearer " + jwt) - .when() + .when() .post(url) - .then() + .then() .statusCode(is(SC_OK)) .extract().body().as(TicketResponse.class); @@ -123,9 +129,9 @@ void givenNoToken() { given() .contentType(JSON) .body(ticketRequest) - .when() + .when() .post(url) - .then() + .then() .statusCode(is(SC_UNAUTHORIZED)) .body("messages.find { it.messageNumber == 'ZWEAG131E' }.messageContent", equalTo(expectedMessage)); } @@ -139,9 +145,9 @@ void givenInvalidTokenInCookie() { .contentType(JSON) .body(ticketRequest) .cookie(COOKIE, jwt) - .when() + .when() .post(url) - .then() + .then() .statusCode(is(SC_UNAUTHORIZED)) .body("messages.find { it.messageNumber == 'ZWEAG130E' }.messageContent", equalTo(expectedMessage)); } @@ -155,9 +161,9 @@ void givenInvalidTokenInHeader() { .contentType(JSON) .body(ticketRequest) .header("Authorization", "Bearer " + jwt) - .when() + .when() .post(url) - .then() + .then() .statusCode(is(SC_UNAUTHORIZED)) .body("messages.find { it.messageNumber == 'ZWEAG130E' }.messageContent", equalTo(expectedMessage)); } @@ -176,9 +182,9 @@ void givenNoApplicationName() { given() .cookie(COOKIE, jwt) - .when() + .when() .post(url) - .then() + .then() .statusCode(is(SC_BAD_REQUEST)) .body("messages.find { it.messageNumber == 'ZWEAG140E' }.messageContent", equalTo(expectedMessage)); @@ -186,18 +192,18 @@ void givenNoApplicationName() { @Test void givenInvalidApplicationName() { - String expectedMessage = "The generation of the PassTicket failed. Reason: 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."; + String expectedMessage = "The generation of the PassTicket failed. Reason:"; TicketRequest ticketRequest = new TicketRequest(UNKNOWN_APPLID); given() .contentType(JSON) .body(ticketRequest) .cookie(COOKIE, jwt) - .when() + .when() .post(url) - .then() - .statusCode(is(SC_BAD_REQUEST)) - .body("messages.find { it.messageNumber == 'ZWEAG141E' }.messageContent", equalTo(expectedMessage)); + .then() + .statusCode(is(SC_INTERNAL_SERVER_ERROR)) + .body("messages.find { it.messageNumber == 'ZWEAG141E' }.messageContent", containsString(expectedMessage)); } } @@ -210,9 +216,9 @@ void givenNoCertificate() { .contentType(JSON) .body(ticketRequest) .cookie(COOKIE, jwt) - .when() + .when() .post(url) - .then() + .then() .statusCode(is(SC_FORBIDDEN)); } } @@ -226,9 +232,9 @@ void givenInvalidHttpMethod() { given() .contentType(JSON) .body(ticketRequest) - .when() + .when() .get(url) - .then() + .then() .statusCode(is(SC_METHOD_NOT_ALLOWED)) .body("messages.find { it.messageNumber == 'ZWEAG101E' }.messageContent", equalTo(expectedMessage)); } diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/zos/ServicesInfoTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/zos/ServicesInfoTest.java index 97a62915ef..5cf56a9edc 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/zos/ServicesInfoTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/zos/ServicesInfoTest.java @@ -12,25 +12,38 @@ import io.restassured.RestAssured; import org.apache.http.message.BasicNameValuePair; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.*; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import org.zowe.apiml.util.SecurityUtils; import org.zowe.apiml.util.TestWithStartedInstances; import org.zowe.apiml.util.categories.GeneralAuthenticationTest; -import org.zowe.apiml.util.config.*; +import org.zowe.apiml.util.config.ConfigReader; +import org.zowe.apiml.util.config.ItSslConfigFactory; +import org.zowe.apiml.util.config.SslContext; import java.net.URI; import java.util.Collections; import java.util.stream.Stream; import static io.restassured.RestAssured.given; -import static org.apache.http.HttpStatus.*; -import static org.hamcrest.CoreMatchers.*; +import static org.apache.http.HttpStatus.SC_FORBIDDEN; +import static org.apache.http.HttpStatus.SC_OK; +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.core.Is.is; import static org.zowe.apiml.util.SecurityUtils.GATEWAY_TOKEN_COOKIE_NAME; import static org.zowe.apiml.util.http.HttpRequestUtils.getUriFromGateway; -import static org.zowe.apiml.util.requests.Endpoints.*; +import static org.zowe.apiml.util.requests.Endpoints.ROUTED_SERVICE; +import static org.zowe.apiml.util.requests.Endpoints.ROUTED_SERVICE_NOT_VERSIONED; /** * Verify it's possible to retrieve information about services onboarded to the gateway if the user requesting the @@ -146,14 +159,15 @@ void givenValidToken() { @Nested class ReturnForbidden { + @Test @SuppressWarnings({"squid:S2699", "Assets are after then()"}) - void givenInvalidCredentials() { + void givenValidUnauthorizedCredentials() { String expectedMessage = "The user is not authorized to the target resource:"; //@formatter:off given() - .auth().basic(UNAUTHORIZED_USERNAME, new String(UNAUTHORIZED_PASSWORD)) + .auth().basic(UNAUTHORIZED_USERNAME, UNAUTHORIZED_PASSWORD) .when() .get(getUriFromGateway(ROUTED_SERVICE)) .then() diff --git a/integration-tests/src/test/java/org/zowe/apiml/util/categories/TestsNotMeantForZowe.java b/integration-tests/src/test/java/org/zowe/apiml/util/categories/TestsNotMeantForZowe.java index c9c73b007f..bc670205c3 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/util/categories/TestsNotMeantForZowe.java +++ b/integration-tests/src/test/java/org/zowe/apiml/util/categories/TestsNotMeantForZowe.java @@ -27,4 +27,7 @@ @Target({ TYPE, METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface TestsNotMeantForZowe { + + String value() default ""; } + diff --git a/integration-tests/src/test/java/org/zowe/apiml/util/config/ConfigReader.java b/integration-tests/src/test/java/org/zowe/apiml/util/config/ConfigReader.java index 23932c8e1c..d2d6a37e63 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/util/config/ConfigReader.java +++ b/integration-tests/src/test/java/org/zowe/apiml/util/config/ConfigReader.java @@ -17,6 +17,9 @@ import java.io.File; import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Objects; import static org.zowe.apiml.util.requests.Endpoints.ROUTED_SERVICE; @@ -25,7 +28,7 @@ public class ConfigReader { private static final String PASSWORD = "password"; - private static String configurationFile; + private static final String configurationFile; static { configurationFile = "environment-configuration" + System.getProperty("environment.config", "") + ".yml"; @@ -40,7 +43,15 @@ public static EnvironmentConfiguration environmentConfiguration() { if (instance == null) { final String configFileName = configurationFile; ClassLoader classLoader = ClassLoader.getSystemClassLoader(); - File configFile = new File(Objects.requireNonNull(classLoader.getResource(configFileName)).getFile()); + File configFile = null; + try { + Path path = Paths.get(Objects.requireNonNull(classLoader.getResource(configFileName)).toURI()); + configFile = path.toFile(); + } catch (URISyntaxException exception) { + log.error("Incorrect environment-configuration.yml location: " + exception.getMessage(), exception); + configFile = new File(Objects.requireNonNull(classLoader.getResource(configFileName)).getFile()); + + } ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); EnvironmentConfiguration configuration; try { @@ -49,8 +60,8 @@ public static EnvironmentConfiguration environmentConfiguration() { log.warn("Can't read service configuration from resource file, using default: http://localhost:10010", e); Credentials credentials = new Credentials("user", "user"); GatewayServiceConfiguration gatewayServiceConfiguration - = new GatewayServiceConfiguration("https", "localhost", 10010, 10017, 1, "10010", ROUTED_SERVICE); - DiscoveryServiceConfiguration discoveryServiceConfiguration = new DiscoveryServiceConfiguration("https", "eureka", "password", "localhost","localhost", 10011,10021, 1); + = new GatewayServiceConfiguration("https", "localhost", null, 10010, 10017, 1, "10010", ROUTED_SERVICE); + DiscoveryServiceConfiguration discoveryServiceConfiguration = new DiscoveryServiceConfiguration("https", "eureka", "password", "localhost", "localhost", 10011, 10021, 1); DiscoverableClientConfiguration discoverableClientConfiguration = new DiscoverableClientConfiguration("https", "ZOWEAPPL", "localhost", 10012, 1); TlsConfiguration tlsConfiguration = TlsConfiguration.builder() @@ -66,7 +77,7 @@ public static EnvironmentConfiguration environmentConfiguration() { AuxiliaryUserList auxiliaryUserList = new AuxiliaryUserList("user,password"); - ZosmfServiceConfiguration zosmfServiceConfiguration = new ZosmfServiceConfiguration("https", "zosmf.acme.com", 1443, "zosmf"); + ZosmfServiceConfiguration zosmfServiceConfiguration = new ZosmfServiceConfiguration("https", "zosmf.acme.com", 1443, "zosmf", ""); IDPConfiguration idpConfiguration = new IDPConfiguration("https://okta-dev.com", "user", "user", "alt_user", "alt_user"); SafIdtConfiguration safIdtConfiguration = new SafIdtConfiguration(true); OidcConfiguration oidcConfiguration = new OidcConfiguration(""); @@ -91,10 +102,11 @@ public static EnvironmentConfiguration environmentConfiguration() { } configuration.getCredentials().setUser(System.getProperty("credentials.user", configuration.getCredentials().getUser())); - configuration.getCredentials().setPassword(System.getProperty("credentials.password", new String(configuration.getCredentials().getPassword()))); + configuration.getCredentials().setPassword(System.getProperty("credentials.password", StringUtils.isEmpty(configuration.getCredentials().getPassword()) ? "" : configuration.getCredentials().getPassword())); configuration.getGatewayServiceConfiguration().setScheme(System.getProperty("gateway.scheme", configuration.getGatewayServiceConfiguration().getScheme())); configuration.getGatewayServiceConfiguration().setHost(System.getProperty("gateway.host", configuration.getGatewayServiceConfiguration().getHost())); + configuration.getGatewayServiceConfiguration().setDvipaHost(System.getProperty("gateway.dvipaHost", configuration.getGatewayServiceConfiguration().getDvipaHost())); configuration.getGatewayServiceConfiguration().setPort(Integer.parseInt(System.getProperty("gateway.port", String.valueOf(configuration.getGatewayServiceConfiguration().getPort())))); configuration.getGatewayServiceConfiguration().setExternalPort(Integer.parseInt(System.getProperty("gateway.externalPort", String.valueOf(configuration.getGatewayServiceConfiguration().getExternalPort())))); configuration.getGatewayServiceConfiguration().setInstances(Integer.parseInt(System.getProperty("gateway.instances", String.valueOf(configuration.getGatewayServiceConfiguration().getInstances())))); @@ -155,9 +167,12 @@ public static EnvironmentConfiguration environmentConfiguration() { private static void verifyTlsPaths(EnvironmentConfiguration env) { TlsConfiguration tlsConfig = env.getTlsConfiguration(); - if (!new File(tlsConfig.getKeyStore()).exists()) throw new RuntimeException(String.format("%s does not exist", tlsConfig.getKeyStore())); - if (!new File(tlsConfig.getClientKeystore()).exists()) throw new RuntimeException(String.format("%s does not exist", tlsConfig.getClientKeystore())); - if (!new File(tlsConfig.getTrustStore()).exists()) throw new RuntimeException(String.format("%s does not exist", tlsConfig.getTrustStore())); + if (!new File(tlsConfig.getKeyStore()).exists()) + throw new RuntimeException(String.format("%s does not exist", tlsConfig.getKeyStore())); + if (!new File(tlsConfig.getClientKeystore()).exists()) + throw new RuntimeException(String.format("%s does not exist", tlsConfig.getClientKeystore())); + if (!new File(tlsConfig.getTrustStore()).exists()) + throw new RuntimeException(String.format("%s does not exist", tlsConfig.getTrustStore())); } private static void setZosmfConfigurationFromSystemProperties(EnvironmentConfiguration configuration) { diff --git a/integration-tests/src/test/java/org/zowe/apiml/util/config/ConfigReaderZaasClient.java b/integration-tests/src/test/java/org/zowe/apiml/util/config/ConfigReaderZaasClient.java index 8368aef062..b50f48857f 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/util/config/ConfigReaderZaasClient.java +++ b/integration-tests/src/test/java/org/zowe/apiml/util/config/ConfigReaderZaasClient.java @@ -10,6 +10,7 @@ package org.zowe.apiml.util.config; +import org.apache.commons.lang3.StringUtils; import org.zowe.apiml.zaasclient.config.ConfigProperties; import static org.zowe.apiml.util.config.ConfigReader.environmentConfiguration; @@ -18,8 +19,9 @@ public class ConfigReaderZaasClient { public static ConfigProperties getConfigProperties() { + GatewayServiceConfiguration gatewayConfig = environmentConfiguration().getGatewayServiceConfiguration(); return ConfigProperties.builder() - .apimlHost(environmentConfiguration().getGatewayServiceConfiguration().getHost()) + .apimlHost(StringUtils.isNotBlank(gatewayConfig.getDvipaHost()) ? gatewayConfig.getDvipaHost() : gatewayConfig.getHost()) .apimlPort(environmentConfiguration().getGatewayServiceConfiguration().getPort() + "") .apimlBaseUrl(ROUTED_AUTH) .keyStorePath(environmentConfiguration().getTlsConfiguration().getKeyStore()) diff --git a/integration-tests/src/test/java/org/zowe/apiml/util/config/GatewayServiceConfiguration.java b/integration-tests/src/test/java/org/zowe/apiml/util/config/GatewayServiceConfiguration.java index 93c1f7500e..d2a5274440 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/util/config/GatewayServiceConfiguration.java +++ b/integration-tests/src/test/java/org/zowe/apiml/util/config/GatewayServiceConfiguration.java @@ -20,6 +20,7 @@ public class GatewayServiceConfiguration { private String scheme; private String host; + private String dvipaHost; private int port; private int externalPort; private int instances; diff --git a/integration-tests/src/test/java/org/zowe/apiml/util/config/ZosmfServiceConfiguration.java b/integration-tests/src/test/java/org/zowe/apiml/util/config/ZosmfServiceConfiguration.java index 1dd0cb9778..2620dd9ce3 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/util/config/ZosmfServiceConfiguration.java +++ b/integration-tests/src/test/java/org/zowe/apiml/util/config/ZosmfServiceConfiguration.java @@ -22,4 +22,5 @@ public class ZosmfServiceConfiguration { private String host; private int port; private String serviceId; + private String contextRoot; } diff --git a/keystore/README.md b/keystore/README.md index fd577f71d3..ffd303f2c4 100644 --- a/keystore/README.md +++ b/keystore/README.md @@ -14,125 +14,140 @@ The last section of this README describes how to import and trust the local CA c ## Key stores: - * `keystore/local/localhost.keystore.cer` - - convenience - - contains the exported server certificate signed by the local CA and private key for the server - - * `keystore/local/localhost.keystore.key` - - convenience - - contains the exported private key - - * `keystore/local/localhost.pem` - - convenience - - contains the exported server certificate in PEM format for use with http clients - - * `keystore/local/localhost.keystore.p12` - - password: ``password`` - - used for the HTTPS server(s) - - contains the server certificate signed by the local CA and private key for the server - - * `keystore/local/localhost.truststore.p12` - - password: ``password`` - - used for HTTPS clients (e.g. integration tests, services using the gateway) - - contains the root certificate of the local CA (not the server certificate) - - * `keystore/local/localhost2.keystore.p12` - - password: ``password`` - - used for tests only, please refer to the particular tests for detils - - * `keystore/local/localhost2.truststore.p12` - - password: ``password`` - - used for tests only, please refer to the particular tests for detils +* `keystore/local/localhost.keystore.cer` + * convenience + * contains the exported server certificate signed by the local CA and private key for the server + +* `keystore/local/localhost.keystore.key` + * convenience + * contains the exported private key + +* `keystore/local/localhost.pem` + * convenience + * contains the exported server certificate in PEM format for use with http clients + +* `keystore/local/localhost.keystore.p12` + * password: ``password`` + * used for the HTTPS server(s) + * contains the server certificate signed by the local CA and private key for the server + +* `keystore/local/localhost.truststore.p12` + * password: ``password`` + * used for HTTPS clients (e.g. integration tests, services using the gateway) + * contains the root certificate of the local CA (not the server certificate) + +* `keystore/local/localhost2.keystore.p12` + * password: ``password`` + * used for tests only, please refer to the particular tests for detils + +* `keystore/local/localhost2.truststore.p12` + * password: ``password`` + * used for tests only, please refer to the particular tests for detils ### Local CA: - * `keystore/local_ca/localca.cer` - - public certificate of local CA - - * `keystore/local_ca/localca.keystore.p12` - - private key of the local CA +* `keystore/local_ca/localca.cer` + * public certificate of local CA + +* `keystore/local_ca/localca.keystore.p12` + * private key of the local CA ### Client certificates: - * `keystore/client_cert/ca/apiml_ca.p12` +* `keystore/client_cert/ca/apiml_ca.p12` API ML External Certificate authority - Certificate and private key of additional certificate authority that is trusted by apiml and can sign certificates that are used for authentication. Convenience export only. -* `keystore/client_cert/client-certs.p12` +* `keystore/client_cert/client-certs.p12` Client certificates - used for testing of client certificate authentication functionality. APIMTST, USER and UNKNOWNUSER. Keystore containing all the above including private keys. Used for testing client certificate authentication functionality. - - - * `keystore/client_cert/openssl.conf` +* `keystore/client_cert/openssl.conf` openssl Configuration for certificate generation ### Certificates for NGINX proxy (for AT-TLS simulation): The following files are used by the NGINX proxy to simulate AT_TLS on the CI server: - * `keystore/localhost/Zowe_Service_Zowe_Development_Instances_Certificate_Authority_.cer` - * `keystore/localhost/localca.cer` - * `keystore/localhost/trusted_CAs.cer` +* `keystore/localhost/Zowe_Service_Zowe_Development_Instances_Certificate_Authority_.cer` +* `keystore/localhost/localca.cer` +* `keystore/localhost/trusted_CAs.cer` ## Generate your own certificates for localhost ### (Optional)Generate certificate authority + create private key -``` + +```bash openssl genrsa -out local_ca.key 2048 ``` + create certificate -``` + +```bash openssl req -x509 -new -nodes -key local_ca.key -sha256 -days 1825 -out local_ca.pem ``` + ### Generate certificate #### generate CSR together with private key in PEM format +```bash openssl req -newkey rsa:2048 -nodes -keyout localhost.key -sha256 -out localhost.csr -outform PEM +``` **Verify CSR** +```bash openssl req -text -noout -verify -in localhost.csr +``` Example of a valid CSR: -``` -Certificate Request: -Data: -Version: 1 (0x0) -Subject: C = CZ, ST = Czechia, L = Prague, O = Broadcom Inc, OU = IT, CN = localhost -Subject Public Key Info: -Public Key Algorithm: rsaEncryption -RSA Public-Key: (2048 bit) -Modulus: -... -Exponent: 65537 (0x10001) -Attributes: -Requested Extensions: -X509v3 Key Usage: -Key Encipherment, Data Encipherment -X509v3 Extended Key Usage: -TLS Web Client Authentication, TLS Web Server Authentication -X509v3 Subject Alternative Name: -DNS:localhost, DNS:127.0.0.1 - Signature Algorithm: sha1WithRSAEncryption -... +```plaintext + Certificate Request: + Data: + Version: 1 (0x0) + Subject: C = CZ, ST = Czechia, L = Prague, O = Broadcom Inc, OU = IT, CN = localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + ... + Exponent: 65537 (0x10001) + Attributes: + Requested Extensions: + X509v3 Key Usage: + Key Encipherment, Data Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Subject Alternative Name: + DNS:localhost, DNS:127.0.0.1 + Signature Algorithm: sha1WithRSAEncryption + ... ``` #### sign the request using CA, this will produce certificate in PEM format -``` + +**Note:** You may need to export the public and private key in PEM format from the local CA keystore + +With PWD as /keystore/local_ca, run the following comnmand: + +```bash openssl x509 -req -in localhost.csr -CA local_ca.pem -CAkey local_ca.key \ --CAcreateserial -out localhost.crt -days 1825 -sha256 -extfile keystore/client_cert/openssl.conf -extensions v3_req +-CAcreateserial -out localhost.crt -days 1825 -sha256 -extfile .../client_cert/openssl.conf -extensions v3_req ``` Use the following script to display the certificate content: +```bash openssl x509 -in localhost.pem -text -noout +``` Example of a valid signed certificate: +```plaintext Certificate: Data: Version: 3 (0x2) @@ -159,24 +174,28 @@ Example of a valid signed certificate: DNS:localhost, DNS:127.0.0.1 Signature Algorithm: sha256WithRSAEncryption ... +``` #### Create PKCS12 truststore and keystore Create truststore -``` + +```bash keytool -import -alias local-ca -file local_ca.pem -keystore localhost.truststore.p12 -storetype pkcs12 ``` Convert certificate to PKCS12 package -``` + +```bash openssl pkcs12 -export -out keystore.p12 -in localhost.crt -inkey localhost.key -name localhost -macalg SHA1 ``` Create keystore -``` +```bash keytool -J-Dkeystore.pkcs12.legacy -importkeystore -srckeystore mvsde12-keystore.p12 -destkeystore localhost.keystore.p12 -storetype pkcs12 ``` + **(optional) use legacy flag `-J-Dkeystore.pkcs12.legacy` in case you want ZSS to use this keystore** ### Trust certificates of other services @@ -193,32 +212,34 @@ You can add a public certificate to the API ML trust store by calling in the dir Issue the following script: +```bash keytool -import -alias -file -keystore localhost.truststore.p12 -storetype pkcs12 +``` ## Import the root certificate of a local CA to your browser -**Warning!** Be sure to only import the pre-generated certificate to a browser that you use for development and testing. Note that the private key is accessible to anyone. +**Warning!** Be sure to only import the pre-generated certificate to a browser that you use for development and testing. Note that the private key is accessible to anyone. -Import [keystore/local_ca/localca.cer](/keystore/local_ca/localca.cer) to your root certificate store and trust it. +Import [keystore/local_ca/localca.cer](/keystore/local_ca/localca.cer) to your root certificate store and trust it. * For **Windows**, run the following command as an administrator: + ```bash + certutil -enterprise -f -v -AddStore "Root" keystore/local_ca/localca.cer ``` - certutil -enterprise -f -v -AddStore "Root" keystore/local_ca/localca.cer - ``` - You have to open the terminal as administrator. This will install the certificate to the Trusted Root Certification Authorities. + You have to open the terminal as administrator. This will install the certificate to the Trusted Root Certification Authorities. **Note:** You can use `npm run register-certificates-win` to run the preceding command. This requires `sudo` to be installed. If you don not have `sudo` available, install [chocolatey](https://chocolatey.org/docs/installation#install-downloaded-nuget-package-from-powershell), then run `chocolatey install sudo`. - -* For **MacOS**, run the following command: - ``` - $ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain keystore/local_ca/localca.cer + +* For **MacOS**, run the following command: + ```bash + $ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain keystore/local_ca/localca.cer ``` Firefox uses its own certificate truststore. You can manually import your root certificate via the Firefox settings, or force Firefox to use the Windows trust store: Create a new Javascript file firefox-windows-truststore.js at C:\Program Files (x86)\Mozilla Firefox\defaults\pref with the following content: - ``` - /* Enable experimental Windows trust store support */ - pref("security.enterprise_roots.enabled", true); + ```js + /* Enable experimental Windows trust store support */ + pref("security.enterprise_roots.enabled", true); ``` ### Disabling certificate validation on localhost @@ -227,10 +248,10 @@ The default configuration of services for local development is to verify certifi Follow these steps to quickly register an existing service without generating a certificate for it -1. Set the `apiml.security.ssl.verifySslCertificatesOfServices` configuration property to `false` from the default `true` for API ML services (Gateway, Discovery service and API Catalog). +1. Set the `apiml.security.ssl.verifySslCertificatesOfServices` configuration property to `false` from the default `true` for API ML services (Gateway, Discovery service and API Catalog). 2. Add the following options to the startup command of each service in `package.json` or in your IDE: - ``` - --apiml.security.ssl.verifySslCertificatesOfServices=false + ```bash + --apiml.security.ssl.verifySslCertificatesOfServices=false ``` diff --git a/keystore/client_cert/client-certs.p12 b/keystore/client_cert/client-certs.p12 index cc8759a2ebb5c93a6a1d790a4650674fbb25c521..ed81104bb8b0fec2249a706d47d8390542281d02 100644 GIT binary patch delta 6057 zcmV;a7gp%oJLp6`FoGgv0s#Xsf+8IT2`Yw2hW8Bt2LYghA`S$CA__2qA_g#m5LyNa zDuzgg_YDCD0ic2qO9X-tM=*jAL$i?utO|bxl?DqchDe6@4FL=a0Ro_c1wb%@1w1fj z1_>&LNQU+thDZTr0|Wso1Q6b8_XqkYIwu&&mlo|Z^Co`; zf&|b$-5kAWicXVIX^ns)>|RqII0XC0BhbU@(^g${)orRGXq#+9tZ za0UiX2&Ge(FDG$iCu61HWoNCMMqIumQM`YlLzCa_^AHpn4fNR25;O??oGJOH^#?KZkc+JH zSv-#{Lwt+EemS48*_sH|FVqa8WxcJ7k))$43&SrLr(Yj=O+F+X|I zGs#qE?L(wkT9olI_B!%%%kCq{E%l{ioo_6FRSwAVzaSFIJ4~$_<+`j5gf@GG9&MhfK?< z!WNXGr{P_Rb5E2j;?{Y)izTRQw2o{6zoCb?SR={?6g>yP8zK`9J46s0w5FMe5yYDe>coE*OpT(q)tca6 zj@e;2(d;o5R0-y$NvZ;rKa2yC|4vXcZr!duaU`@-ehk621xjI``c)s<6#3RPnW$fo zRel_8f0Qe5I9_oC7rCj2Hj{r+$(aA-$?uZRZehr#9u!KRpecR$5WUlY;8nPujmTi5 z2!!({2?xoQ;GaB_2b+JycNapMKzAF+^DUxmm)pNsAj;kM3t|z5{1{gv@hIuPi)8hU zJEypz0i+@%3S1IDuzKyV0cIJ*au5)bLl3vTArdXyeRH%V;yXE#XKcb_jYfjW9D+n`kqtV z%-Kf9Jy*8i7<#&`x;mIOWuf)@6v6>oZyagev0fOY-E z(6Mf+v{Rsd5_6khbd`1zjkC8oInpOAjMy{qmTIo#z;{dLsoI+YnkZ|OZ1KfJ=dD>H>nEM&)^7hcEFOu+f<^5LHFN0l z^1Q-X+4o&`YGuiDYQ~gO9^`v6go1>qP*)JM%{j80iL)@Xe)4=e!v$6T>>fsNh5C4P z3gJKITGghL*8jH-?2iD@lNbrxjSBZVHX-24ylnpJ?MVBuH^f4<`>nMRMsOtJlT8IU zDmODYF*P|gGdVLdI52_{qy`BphDe6@4FLxRpn?&VFoF@00s#Opf)R?7Sr8q6y}JLQ zAdwwXl>!kotugw_NvpB70s{cUP=JCFP%4bFZ2rlRwDP*SE@K(>x$HJv3+iQA2C0cJHPBkmF_SKi+agH zg#&o&_**zLoAk;C&OY8XgOF?AE$abR0qv*W8@gyoU^x<@NUNHzz2;AUn8CPpSOlBj zYP<7LrgUWj!z!cWe_mPC>TA!Tnn&?6#xs5y#z{7*n;fSo*R4Yd%)!mAwp;PDKRQWf zB!9y)5-o^YOb7f%cotE2^NO?x@)5t^(MJVlqPGZsQ)h8mKOX5R1FT6iV;Fo+2(`Ji z4FBt{=}-t7#1U3m7Y&(z3C&ihb|zixO$%FbTI>rChAG&YJ;D zVaMQ>H&`jT_iL0dobV#}dS>cGt- zpgk1bgloDNBJWw>&F+5cCtn23VdpZ`v|+34-^akol&aE38=%U6fUq+M`R|+6-AD4^ z7;f#a!!i8sgeG9O1o9zayMsxryh%mHYQ;A_UXr|uuO?4A@K%w_S8g15`)NxF$&zB+Qpbg6voQWha6(abOZ2ZO4ti+Tk6 zoBIiJd^bY@l`1zQ3_~f?Wo08Dwh7mTm+FLO`rH!97;>oCZXhqd2aozeLpa#|(jctW z&Eg_a$MlqcEfM|hLIH1>B=iI_iNl>S?n3KixyQSc`!*?*qI`m-U}3S_pMB5!3kWQN zsy-toDbO}%Bd*>I6_FMPMBmZZeLbzuc(wB7;;VvDS^0_7{`g^VHFfMz45ZD>)u8X}#UR8mbuOm__=CKaT zK1rbhJZsDM@9@t6!NI4#wWWmPv#ZfpjDedW_T_#O+~{VV(OI3l_mh{5_)ilKrEwSc zOm`Azy9;Mk@`0xiuVv0p2naDM*_tUd`$0%3?BeWGQSx%X;wa{I9KZwvxRwkNVMzAi zk@CKOIVY_v)ituk6~G#ERgHjs`jpd=)Yg_opTClqUz3jh;lE%&_3sGa71149ergx8 z$eAWw;EZ3^UU!tS=3`6f*@R-3{PaI6jkKVvJjtwP+LIzat|3S29Dhe8N>2y8MUBXG zR~76^xq5qzxOYtCzOx53ivpiYA``v_0&PNnM;u!dnPx#aH&clFX$)XXw!iV`XEn<# zhl0Cby1(e|X2L(@S^;5I-&(EjnGwXHKBmEMU6|zm3-{^3M(P)nXy)IPqfuo`wM+B0 zd1iUpTxl@$BP|u0-WX@O!_OFJR5fp&WCd`4*2Ee^o~=g3$_LADLj_N}2Y6mq62Mx2 z92LY3THMaupWBp3jzS&S;CJlE4#kJ;AS0JZge5S%LCnb`m!Kq4FYsz%q*U zHR+UD9H75eS(+`#{(!J;Ad&33FTH_R3j=z4DtqP(aTk2^$Y1%z=Iv2cO9!j@x&2*3 z>!m=qfx*ZhRd&6Z9{%#1;C)V1r-~AH;4uGZ$QC0BCRkuve&bmc#cJ;yW1de&axO-e z-%-(#nDq9p?DzNbYLMxNn{v^Adnf}%(Ni!>CVqUPRU1;yS0+4JMxt6}Kov2VPkrK( z>0P0-Kp;$4C~jH?Luz4NyoR+ppe|SwIRcJX(n1ShaRGGI0REk(RJN1bd`7d5hN@zs zK{yxD?Lur8PA-VL$`*21R;X{Ag?GrJ=`?8rO3J7A{ukG@*#$QFbVVkAwKWp!X7uOd z7)f5B#gz!vj;?rw_@rs6Vd%>yZht$USn(|%w=QM9F7*dGQkt z%;3Xs{>aL?`Oc*=xxH$C7|kbT^J{FEF01-vjSLx5t+z233)^62$gz)>a_oH2q@HYDjJฟNE^Y}!ny@&U zF+*+D>X}~%)8pCX{ea@Ky@SV^HYA^Dd>fWMxp5EW>++D`ea@7Bo`M|1?sxqFloZ2B zQf{L&gsj55v59iW4YqvIH<+rrz3BXkrPiyvfHB@idU*w!0r;n-cJ)Q4r6|M0oG98E z_|F%){I4y||B+ttIvJw?<;W<-z4evpf?~oWa8}?&A>ua4oBwV?jJyBf7_`o>eO-s1 zS75CrGfZdnx3_A4Kj0@0#>dF}UI`D!s9VYqR#7QtAgN5;aPZ8-O^uI>i+7}yq`ML< z_$fy|B5SWDCD+drvu zSlgf`uew784OLgW`uqA|Z`Z|2puS+FND^g~R^AkUKfxU7q)-_y53eG_2`j4<3Hsph z)rdrA@cWeX^%3sY%3fw6SJ+{f{g-Y{=_R`#Xi;jW#wPp#&>iT|XMvwr#Rs*+5VaY( z5G-!2-NE=EUz=ULv3zlOB+}Z856?On$Hnqsy0cM|Yu^<9v$2nlk9~jA^U`(Txy;Y! z12e9F?JU=ray&evpI{>%FHKB+N(#F49pyyE2(PzJoUXE89g(9zH3g+;Uac=LLLL)t z56WlU38oGNA282;aBoD!vl z4=NlUj|wCx_j9XJW`E{TiB?pR%hnmuDi`H{&Jmu)6gto=deO-ZFMUCxOy@g_@nh#? zn5Q_YiQKL`nwFa_xdNV=yJ)i$ihwutotT5pVGKQp+xx@jD>_RfYf7*bhkuNmii1sd zyLu~Ag~z|$ds1Jm;p;%S=eS?J4jea^n`r0smhW}w%6E1kYfY%F4>C0B7GbgdKPLHq zZ_ zuX~`rfsrF;Zlv4#mVG*r)uRI$J+EGY02s39)kq%{=zoyK=&q9v=vPg&l`xp0r7)$`qNT{Si$z&kJvzCU!CJv#fzEtNf~e?aRY@A^B2vaSZFa_Dtsa=NcF~7FCL0`M#U5O!64% z@u8z%jwPtI0yB+g`A<354ep_`vQLQ z|6&}Dj=Rs5g~=lGljL9jm17GMJ&6EI^246Nw6ca^P7jQobsa z8IIbZbz+AeSjdgkq-()nzKf$eXWQR@BuPO|Dl*w3v67q6-cC~&B{9mNS!j>ZVXX)e zN*mOrd%yiK7fwQ;53IU1`^wnkhYMKVtML~le5}xiEN_P8n;Ehq5DjLx`f7_c)agz^ zI{3Q9+Tef^TTL8f9fhfX6Om~6R21weqUiHU8>0`V*9U=mV*Xpfr7I zl4E`HREMG07bqBhxF^o1ll86#@@U3_u{_bNn}qxSXCUXez&!PmHe7n-@})M-) z5}1la0Sr0&nwY5ANWv4e$4$~-^e8|07wTzIEb81X>u6Kwu)6^rO@x9=AaSQ!BCQR4 zZva;;KbZPiat;iC>fJPr&q7_FEan`;z-9XI>_xi-IiNb9R9ZCx6(_A9Eu@!a#`_)L zy^mwe^&gsKEbL>~1>xCKZ4X@uWyOE!D6G;gFN&3nC04?)(}0rEJvf|(N`18Ld}&qR zzS;O92c4)q_v3|DDDxU1<#glg4>!^!dapud`r(yQP&==Gsq*pf-nbk};dtkPhttH*B2YdTLosf0S(Y90+SEhdUe&LMaKFxC zkS;sAze9ThtuY#cPFG&Cpk?*0WuQ|FBp`OMGQV^}XasP!sdkgI zC*j6d#U1blSmo8bH-0g0>9odTLDJ*t^v9G2?U%TN-VM(-!*6;8&2m%8D z!%zf*1jwv<=K6qEwDy3^-q_Cu(qq^e(pxna)Sq4au7f*`@x*aWg~$6I7C7n`NkAO>S6AaJ!Vp0>%S9nWc1&qPg6aM6(t89tWGZH=Ujr{WaD{3@ zf8~xSzzO2=ND?!4svEx$3FY~RZ3g^-`b{#nR@LJZ5Fh0e%AmTCYlfdh94EUT=f(6W zYJEM9H;zss2+M5BZFg*RIA<@UC6f0I@zU?FHzO7I6_E3&T490B7*P(#}rr(y!S zHxOnqe%QF&>eCa>UQ?#%3Nrqk@lN~l`;I~@t3gQ)_q zjRp1F;E4##5L%+LSMKe_5pXXN(X0(W<;qN>F*al$zK2AAPY57Fav@*_yUP;h6YIxo@Hg9$JM+`Qk5A1R=c03_7er z=uX(kR+Y)uF7s^{Eap$JGraLBvSN6=XsXbpBoP63)5KZw+Rs7YNAAoz#GgqAZ2w8c zQhE$h!r2aRRwIM@^gaX4e}A20E1okC#Sw}-ez<_68A7`J!)wn%yX(flQuB*XS&Emv z&NQ%(zvMBA3Pjde6#;sTkUmM{2A4^zL(oV>QQC7&Ug58EA$Y2YpZ zwo;4_?Z2%P!0Tl7TLA)dmn&-v9ib9$RO!ym@9l#d{+<-Md_>`w{3wS+*_aAgK@~{3 zC@D}Qu#2ABBY<$Fe_#2Ha+(l*KEXE7ZOXVNGJI$*%*Y?k9Kr2WwqBO1azsyL%7+W^ zal*M&mEproZe5je68H;URnO60yK^_xj8uQtC0?^yfiB3yz|o{7K*=pv98xeaZARx) z%Y_hD^fWz-a6lGQo!tm|9jXS?QqL|*fA;~io!Dl79VQpzf2AOkN(HF+OkX^$#WyU! zF_24QMLua1hXTJchS&~7AN7@X;hT0)6I#43I2ugsn%LE}&(y^+LNFZ$2`Yw2 zhW8Bt2^299lT8pOlYa#V1vN7twPxE15*P7<)xmIp0(!R61hXz0s{cUP=JCB2ofslY$^T{65zc#O5_PDR9G4y<6P`kZc<+H;gbz)oRdze{MBON95WU*sNfw$k#J9 zy5jvs`VDa4M5NL9mSV2qF(aWSniOsYJs;*2VCJ4n^l6F8!hkR^>^%oCIi+#bXNN9_ zp{mAzjz>c5=Cs}kee)-T!Ty_cU`kp~)*)m<{LGM9STbbd zPTwuq%7Ja~=d(0^vZNNzOoIkFv5GaLGP&%3=9pIVq>k5^{*lABoy2O7N#Sbfdbe!AM7eB_m8ktjM|cOIJ@pla^@gcN-JmYjUl(5xSJXS@!_vtHqg8@Y~J2JD3-2;d7CtJ z>cMsjO)2n|Q6XZ^qFv*SreX|Xm{E9t(}n`^yivxE>7~?BekdiEy1a&1{tN_X7UfNZ z;vGXar*Wlpw~P$Eva54wM(Q{+K|p7* z7Y+42FcuS(Suan2bLiaH;RcE2OXzM&{8f69fiTSwP$k!%3Pk)3fuZ!F6~F6WaJh6 zWG2K0&M0x}#e8C7xu9w#qqB2X@YuCpkgr@+8rZtZ`aLs|==Z{nw3)0}9Wj8ZHy8|{ ztgiyQBMRR2D%MoXRa^;wn01AJ=s>q)+ytYt%Zy*=wtq#!*GZneWu65zFGaZpPj!2; zx5FAg(}f1fuVRJ3JPS90{O~v@8H3$gWSd#x1MGWz-NBvB%{kJ<`Ifd3E!okcu|+Ou zYGMrKP!9%26dZ@IPs6$_O8v6X1#$wYXXs~d8hwe8e=M_1Og4r9Z^4RxbkN^^$3^C13&t1nFzG$X zdynJ7*e|-U^sL`~8H0p*>g)RG;W#36+>;9~T!=)J(>;GfbOE6bHWrZf82QA27_mHH zjU@~Wjl8~T1+oDX5QqVPLoUx;c(#?YU$QV!oa1YD^fUByHW8)-+d?NKM8*g=@1G2u z1s0@PWD#Oimcgq>`@`{C2n3OZRdj>Hl*)>PyvBQJH+ctu)7MguS|`dm%>m>4Pqxhz zCRBXHt*<&78e*3)+AZ8ZLow0yXEJYT;0XjI6cJIKsJlf!xvndJ{cz-lP=6#8g@u>7 z?LGTi4v4MX?WLdCvJHW|=KqxRcM4>-vgcECe-ug6St`R{jJHn5b;018yx|YhNi}Ew7cpdaEfU9C4zq5Jtn& zm0|@H@nXGVn&D!9<5_X3JHzDA|FtmTL`2$Ko{UHxjkBsPL>Hm2_=aTgS6mp%1DMg# zTu}5U9J((bP9m#?1x#w#z5K#yMka2sX@QK#rI z0OiqX*%XMk>oCpKAVCbnwS;x*$t$-;78|mxFL3+GndQuXwrrlHKitIQV}qdXF$74F zN-UwR7RZ!4TtlC^!05g-a_8RX}WLa*QMNH$F~FTc$*uCva%k8DjZD8zW}nW>qE5kpw6 z1>YCK1OPsNPdruEs7_9`8STzK4ewL;yY0^H&a85w7s!`VBOg+q=5jk-IBhPxo5Y!V zY?|?vEX9eX0n#zM`$f4>|JmAO7&oxH{a%eU#5HZ=3UzqG%4Ih8TbOAZisP0kHklVr zE2#$Ew){N;UF~ykF{nC=0Nj(sc`0_7U@1K9>}v{t>87nuC={K{IBK^arTvwWkcUV^ zik$PIGEfBiMF$X{t01{*EBfDDTJEHA#ki0;x9g~A&=uc|`KFI!z(p$adY0vF~SUZnnU%puKQ^lSzP|J*AAm???J zu(wU)!b{6<0L7>-=1erYQV?krtH_>FYJ=zi5ILn>HZaOX`p~1eyP%?=yeuHb0(*_7 z$W0oKUp+bFUq<{dOskKs2A1@q&jb?Z$82(c?gm?+VBSm9AbWbygV2N!f55aLq{Tsw zMRgU5j%6roAfm%VVVrW;@kq7vLj* zxWP;V2Ccc zHTyO2urO^n>}4Z`YfNAV#K7ct1k^WFb3TpmLKKz_h+4f)3vT3pJz%6Lu;*&p8v}8tTygkT{g_6YledPl$;t3JDP3*%hRw!*d@{q_ zyPb*q>O0diw^!?>(H(`$t;>F=&6>`=l6YJ!_-b{ifd-yPoQo%kyI4~F)u(oKnfpzU z&qU*yEYjHP5m)`SrCgzbe8Q}pHmI3IE{=}(KmliL;n^qX}2P(f{kW@p!tQEQe;5(^`RdZn3{rPrVluyK{5iSAZrYs_-3849LVlFSdJc*U?vC7 z-R9n)plebtCZ;{K?$d`O@=JLMM$Z267O-+8Z^o46uuH**U|$M};G zVELpvo!Ym<3*%M2g2|?PzMUF#zglQaG-p^^EUT@M>2x*^Kp;or+MhjoTD2-|tdTpA>=)fmFxvS{4QDh@a9%<q@#?4UPfjN(;Xl&jpjG3wa_M_9Zo=fC6%>=3nrlyIX>1O zT}z0sbIMaKosLKxDi^loZkp%ibhw0cML_OhQyxHq{Rf}`<3!2nVC6;mvUZ;AQs|bF zG;E6~%Vh$8DFilRWc(adS%UO^|6a=^>SfxIbS0t>m&nGdJvErvB(&mRG(Km Date: Thu, 27 Feb 2025 13:59:47 +0100 Subject: [PATCH 03/21] fix failing tests Signed-off-by: nx673747 --- .../gateway/GatewayTimeoutTest.java | 7 ++---- .../providers/ZosmfLoginTest.java | 8 +------ .../schemes/PassticketSchemeTest.java | 24 ++++++++++++------- ...rviceProtectedEndpointIntegrationTest.java | 24 ++++++++----------- .../integration/zos/ServicesInfoTest.java | 3 +-- 5 files changed, 30 insertions(+), 36 deletions(-) diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayTimeoutTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayTimeoutTest.java index 5bdc153b65..297ee1d829 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayTimeoutTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayTimeoutTest.java @@ -22,12 +22,11 @@ import org.zowe.apiml.util.categories.DiscoverableClientDependentTest; import java.time.Duration; -import java.util.Collections; import static io.restassured.RestAssured.given; import static org.junit.jupiter.api.Assertions.assertTimeout; import static org.zowe.apiml.util.http.HttpRequestUtils.getUriFromGateway; -import static org.zowe.apiml.util.requests.Endpoints.*; +import static org.zowe.apiml.util.requests.Endpoints.DISCOVERABLE_GREET; @Slf4j @DiscoverableClientDependentTest @@ -51,9 +50,7 @@ void returnGatewayTimeout() { assertTimeout(Duration.ofMillis(DEFAULT_TIMEOUT * 6 + (2 * SECOND)), () -> { given() .when() - .get(getUriFromGateway(DISCOVERABLE_GREET, - Collections.singletonList( - new BasicNameValuePair("delayMs", String.valueOf(DEFAULT_TIMEOUT + SECOND))) + .get(getUriFromGateway(DISCOVERABLE_GREET, new BasicNameValuePair("delayMs", String.valueOf(DEFAULT_TIMEOUT + SECOND)) ) ) .then() diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/ZosmfLoginTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/ZosmfLoginTest.java index 75934f0ad2..b584c0f2fe 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/ZosmfLoginTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/ZosmfLoginTest.java @@ -12,7 +12,6 @@ import io.restassured.RestAssured; import io.restassured.http.Cookie; -import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; @@ -28,8 +27,6 @@ import org.zowe.apiml.util.http.HttpRequestUtils; import java.net.URI; -import java.util.ArrayList; -import java.util.List; import java.util.Optional; import static io.restassured.RestAssured.given; @@ -69,14 +66,11 @@ void givenValidCertificate_thenReturnExistingDatasets() { String dsname1 = "SYS1.PARMLIB"; String dsname2 = "SYS1.PROCLIB"; - List arguments = new ArrayList<>(); - arguments.add(new BasicNameValuePair("dslevel", "sys1.p*")); - given() .config(SslContext.clientCertUser) .header("X-CSRF-ZOSMF-HEADER", "") .when() - .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) + .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, new BasicNameValuePair("dslevel", "sys1.p*"))) .then() .statusCode(is(SC_OK)) .body( diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/PassticketSchemeTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/PassticketSchemeTest.java index d54b6d2988..360e2ee948 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/PassticketSchemeTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/schemes/PassticketSchemeTest.java @@ -27,14 +27,17 @@ import org.junit.jupiter.params.provider.MethodSource; import org.zowe.apiml.constants.ApimlConstants; import org.zowe.apiml.util.TestWithStartedInstances; -import org.zowe.apiml.util.categories.*; +import org.zowe.apiml.util.categories.DiscoverableClientDependentTest; +import org.zowe.apiml.util.categories.GeneralAuthenticationTest; +import org.zowe.apiml.util.categories.InfinispanStorageTest; +import org.zowe.apiml.util.categories.MainframeDependentTests; +import org.zowe.apiml.util.categories.TestsNotMeantForZowe; import org.zowe.apiml.util.config.CloudGatewayConfiguration; import org.zowe.apiml.util.config.ConfigReader; import org.zowe.apiml.util.http.HttpRequestUtils; import java.net.URI; import java.util.Base64; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.stream.Stream; @@ -42,11 +45,18 @@ import static io.restassured.RestAssured.given; import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; import static org.apache.http.HttpStatus.SC_OK; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.core.Is.is; import static org.zowe.apiml.integration.penetration.JwtPenTest.getToken; -import static org.zowe.apiml.util.SecurityUtils.*; +import static org.zowe.apiml.util.SecurityUtils.COOKIE_NAME; +import static org.zowe.apiml.util.SecurityUtils.PASSWORD; +import static org.zowe.apiml.util.SecurityUtils.PAT_COOKIE_AUTH_NAME; +import static org.zowe.apiml.util.SecurityUtils.USERNAME; +import static org.zowe.apiml.util.SecurityUtils.gatewayToken; +import static org.zowe.apiml.util.SecurityUtils.personalAccessToken; import static org.zowe.apiml.util.requests.Endpoints.PASSTICKET_TEST_ENDPOINT; import static org.zowe.apiml.util.requests.Endpoints.REQUEST_INFO_ENDPOINT; @@ -242,10 +252,8 @@ class VerifyPassTicketIsInvalid { void givenIssuedForIncorrectApplId(String token, String cookie) { String expectedMessage = "Error on evaluation of PassTicket"; - URI discoverablePassticketUrl = HttpRequestUtils.getUriFromGateway( - PASSTICKET_TEST_ENDPOINT, - Collections.singletonList(new BasicNameValuePair("applId", "XBADAPPL")) - ); + URI discoverablePassticketUrl = HttpRequestUtils.getUriFromGateway(PASSTICKET_TEST_ENDPOINT, + new BasicNameValuePair("applId", "XBADAPPL")); given() .cookie(cookie, token) diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/services/ServiceProtectedEndpointIntegrationTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/services/ServiceProtectedEndpointIntegrationTest.java index ae6c66cc10..a25d17b9c5 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/services/ServiceProtectedEndpointIntegrationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/services/ServiceProtectedEndpointIntegrationTest.java @@ -23,9 +23,6 @@ import org.zowe.apiml.util.config.ConfigReader; import org.zowe.apiml.util.http.HttpRequestUtils; -import java.util.ArrayList; -import java.util.List; - import static io.restassured.RestAssured.given; import static org.apache.http.HttpStatus.SC_OK; import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; @@ -52,7 +49,7 @@ class ServiceProtectedEndpointIntegrationTest implements TestWithStartedInstance private static final String ZOSMF_ENDPOINT_GW = "/" + ZOSMF_SERVICE_ID + "/api/v1/" + (StringUtils.hasText(ZOSMF_CONTEXT_ROOT) ? ZOSMF_CONTEXT_ROOT + "/" : "") + "restfiles/ds"; private static final String ZOSMF_ENDPOINT = ZOS_TARGET ? ZOSMF_ENDPOINT_GW : ZOSMF_ENDPOINT_MOCK; - private List arguments; + private NameValuePair argument; private String token; @@ -60,8 +57,7 @@ class ServiceProtectedEndpointIntegrationTest implements TestWithStartedInstance void setUp() { RestAssured.useRelaxedHTTPSValidation(); token = SecurityUtils.gatewayToken(USERNAME, PASSWORD); - arguments = new ArrayList<>(); - arguments.add(new BasicNameValuePair("dslevel", "sys1.p*")); + argument = new BasicNameValuePair("dslevel", "sys1.p*"); } //@formatter:off @@ -78,7 +74,7 @@ void viaBearerHeader() { .header("Authorization", "Bearer " + token) .header("X-CSRF-ZOSMF-HEADER", "zosmf") .when() - .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) + .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, argument)) .then() .statusCode(is(SC_OK)) .body( @@ -94,7 +90,7 @@ void viaCookie() { .cookie("apimlAuthenticationToken", token) .header("X-CSRF-ZOSMF-HEADER", "zosmf") .when() - .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) + .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, argument)) .then() .statusCode(is(SC_OK)) .body( @@ -110,7 +106,7 @@ void viaBasicAuthHeader() { .auth().preemptive().basic(USERNAME, new String(PASSWORD)) .header("X-CSRF-ZOSMF-HEADER", "zosmf") .when() - .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) + .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, argument)) .then() .statusCode(is(SC_OK)) .body( @@ -132,7 +128,7 @@ void viaBearerHeader() { .header("Authorization", "Bearer " + invalidToken) .header("X-CSRF-ZOSMF-HEADER", "zosmf") .when() - .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) + .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, argument)) .then() .statusCode(is(SC_UNAUTHORIZED)); } @@ -145,7 +141,7 @@ void viaApimlCookie() { .cookie("apimlAuthenticationToken", invalidToken) .header("X-CSRF-ZOSMF-HEADER", "zosmf") .when() - .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) + .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, argument)) .then() .statusCode(is(SC_UNAUTHORIZED)); } @@ -161,7 +157,7 @@ void withoutAnyAuthenticationMethod() { given() .header("X-CSRF-ZOSMF-HEADER", "zosmf") .when() - .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) + .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, argument)) .then() .statusCode(is(SC_UNAUTHORIZED)); } @@ -174,7 +170,7 @@ void withEmptyHeader() { .header("Authorization", "Bearer " + emptyToken) .header("X-CSRF-ZOSMF-HEADER", "zosmf") .when() - .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) + .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, argument)) .then() .statusCode(is(SC_UNAUTHORIZED)); } @@ -187,7 +183,7 @@ void withEmptyCookie() { .cookie("apimlAuthenticationToken", emptyToken) .header("X-CSRF-ZOSMF-HEADER", "zosmf") .when() - .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, arguments)) + .get(HttpRequestUtils.getUriFromGateway(ZOSMF_ENDPOINT, argument)) .then() .statusCode(is(SC_UNAUTHORIZED)); } diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/zos/ServicesInfoTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/zos/ServicesInfoTest.java index 5cf56a9edc..99027c05c3 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/zos/ServicesInfoTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/zos/ServicesInfoTest.java @@ -29,7 +29,6 @@ import org.zowe.apiml.util.config.SslContext; import java.net.URI; -import java.util.Collections; import java.util.stream.Stream; import static io.restassured.RestAssured.given; @@ -227,7 +226,7 @@ void givenValidTokenWithAuthorizedUserAndValidServiceId() { given() .cookie(GATEWAY_TOKEN_COOKIE_NAME, token) .when() - .get(getUriFromGateway(ROUTED_SERVICE, Collections.singletonList(new BasicNameValuePair("apiId", API_CATALOG_SERVICE_API_ID)))) + .get(getUriFromGateway(ROUTED_SERVICE, new BasicNameValuePair("apiId", API_CATALOG_SERVICE_API_ID))) .then() .statusCode(is(SC_OK)) .header(VERSION_HEADER, CURRENT_VERSION) From 114007f6f4f9b18a4c5178d439370f471930c7e9 Mon Sep 17 00:00:00 2001 From: nx673747 Date: Fri, 28 Feb 2025 15:27:17 +0100 Subject: [PATCH 04/21] specify jdk 8 for the compiliation of discoverable client Signed-off-by: nx673747 --- discoverable-client/build.gradle | 5 +++++ .../src/test/java/org/zowe/apiml/util/SecurityUtils.java | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/discoverable-client/build.gradle b/discoverable-client/build.gradle index 9dada93fdc..a11050d7b3 100644 --- a/discoverable-client/build.gradle +++ b/discoverable-client/build.gradle @@ -10,6 +10,11 @@ plugins { alias(libs.plugins.gradle.git.properties) } +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + normalization { runtimeClasspath { ignore("**/*git.properties*") diff --git a/integration-tests/src/test/java/org/zowe/apiml/util/SecurityUtils.java b/integration-tests/src/test/java/org/zowe/apiml/util/SecurityUtils.java index 931acff571..03759c90fc 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/util/SecurityUtils.java +++ b/integration-tests/src/test/java/org/zowe/apiml/util/SecurityUtils.java @@ -178,7 +178,7 @@ public static String gatewayToken(URI gatewayLoginEndpoint, String username, Str .statusCode(is(SC_NO_CONTENT)) .cookie(GATEWAY_TOKEN_COOKIE_NAME, not(isEmptyString())) .extract().cookie(GATEWAY_TOKEN_COOKIE_NAME); - } finally{ + } finally { RestAssured.config = RestAssured.config().sslConfig(originalConfig); } } @@ -280,7 +280,7 @@ private static String getZosmfToken(String url, String cookie, int expectedCode) .statusCode(is(expectedCode)) .cookie(cookie, not(isEmptyString())) .extract().cookie(cookie); - } finally{ + } finally { RestAssured.config = RestAssured.config().sslConfig(originalConfig); } } From b76acb977a6355f896b79de4ccee43b27b9d4b52 Mon Sep 17 00:00:00 2001 From: nx673747 Date: Wed, 5 Mar 2025 12:18:09 +0100 Subject: [PATCH 05/21] fix failing integration tests Signed-off-by: nx673747 --- .../pat/PATWithAllSchemesTest.java | 24 +++++++++---------- .../integration/zaas/PassTicketTest.java | 3 ++- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java index ba038ffec0..4c61a133ff 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java @@ -61,18 +61,18 @@ static Stream authentication() { static Stream schemas() { List schemasTest = new ArrayList<>(); - schemasTest.add( - Arguments.of("zowejwt", HttpRequestUtils.getUriFromGateway(ZOWE_JWT_REQUEST), (Consumer) r -> { - assertEquals(HttpStatus.SC_OK, r.getStatusCode()); - assertThat(r.getBody().path("headers.cookie"), containsString(COOKIE_NAME)); - String jwt = r.getBody().path("headers.authorization").toString(); - try { - String issuer = JWTParser.parse(jwt.substring(ApimlConstants.BEARER_AUTHENTICATION_PREFIX.length()).trim()).getJWTClaimsSet().toJSONObject().get("iss").toString(); - assertEquals("APIML", issuer); - } catch (ParseException e) { - fail(e); - } - })); + schemasTest.add(Arguments.of("zowejwt", HttpRequestUtils.getUriFromGateway(ZOWE_JWT_REQUEST), (Consumer) r -> { + assertEquals(HttpStatus.SC_OK, r.getStatusCode()); + assertNotNull(r.getBody().path("headers.authorization")); + String jwt = r.getBody().path("headers.cookie").toString(); + assertThat(jwt, containsString(COOKIE_NAME)); + try { + String issuer = JWTParser.parse(jwt.substring(COOKIE_NAME.length()).trim()).getJWTClaimsSet().toJSONObject().get("iss").toString(); + assertEquals("zOSMF", issuer); + } catch (ParseException e) { + fail(e); + } + })); schemasTest.add( Arguments.of("dcpassticket", HttpRequestUtils.getUriFromGateway(REQUEST_INFO_ENDPOINT), (Consumer) r -> { assertEquals(HttpStatus.SC_OK, r.getStatusCode()); diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/PassTicketTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/PassTicketTest.java index 6dd40142e1..6ba88e1bf0 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/PassTicketTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/PassTicketTest.java @@ -34,6 +34,7 @@ import static io.restassured.http.ContentType.JSON; import static io.restassured.http.ContentType.TEXT; import static org.apache.http.HttpStatus.SC_BAD_REQUEST; +import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; import static org.apache.http.HttpStatus.SC_NOT_FOUND; import static org.apache.http.HttpStatus.SC_OK; import static org.hamcrest.CoreMatchers.containsString; @@ -203,7 +204,7 @@ void givenInvalidApplicationName() { .when() .post(ZAAS_TICKET_URI) .then() - .statusCode(is(SC_BAD_REQUEST)) + .statusCode(is(SC_INTERNAL_SERVER_ERROR)) .body("messages.find { it.messageNumber == 'ZWEAG141E' }.messageContent", containsString(expectedMessage)); //@formatter:on } From d3e5f02c4a3aaf828eb3071241eb8398003d9c20 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Fri, 7 Mar 2025 16:34:41 +0100 Subject: [PATCH 06/21] parse cookie Signed-off-by: Pablo Carle --- .../authentication/pat/PATWithAllSchemesTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java index 4c61a133ff..0573a0daa2 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java @@ -64,10 +64,12 @@ static Stream schemas() { schemasTest.add(Arguments.of("zowejwt", HttpRequestUtils.getUriFromGateway(ZOWE_JWT_REQUEST), (Consumer) r -> { assertEquals(HttpStatus.SC_OK, r.getStatusCode()); assertNotNull(r.getBody().path("headers.authorization")); - String jwt = r.getBody().path("headers.cookie").toString(); - assertThat(jwt, containsString(COOKIE_NAME)); + String cookies = r.getBody().path("headers.cookie").toString(); + assertThat(cookies, containsString(COOKIE_NAME)); + String jwt = cookies.substring(cookies.indexOf(COOKIE_NAME)); + jwt = jwt.substring(jwt.indexOf("=") + 1, jwt.contains(";") ? jwt.indexOf(";") : jwt.length()); try { - String issuer = JWTParser.parse(jwt.substring(COOKIE_NAME.length()).trim()).getJWTClaimsSet().toJSONObject().get("iss").toString(); + String issuer = JWTParser.parse(jwt).getJWTClaimsSet().toJSONObject().get("iss").toString(); assertEquals("zOSMF", issuer); } catch (ParseException e) { fail(e); From 7cef278178b24bd901d5b8c4f3bfb06edf42e1f2 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 10 Mar 2025 13:08:15 +0100 Subject: [PATCH 07/21] changes not meant for v2 Signed-off-by: Pablo Carle --- gateway-service/src/main/resources/application.yml | 2 +- .../discovery/DiscoveryServiceAuthenticationTest.java | 2 -- .../apiml/functional/gateway/GatewayAuthenticationTest.java | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/gateway-service/src/main/resources/application.yml b/gateway-service/src/main/resources/application.yml index 9132949a63..ffe653227d 100644 --- a/gateway-service/src/main/resources/application.yml +++ b/gateway-service/src/main/resources/application.yml @@ -225,7 +225,7 @@ management: web: base-path: /application exposure: - include: health,info,shutdown + include: health,info,shutdown,hystrixstream health: defaults: enabled: false diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java index 67b8d68787..d4823063d2 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java @@ -90,7 +90,6 @@ void thenReturnUnauthorized() { } @Test - @TestsNotMeantForZowe("Automation needs unprotected health endpoint") @DisplayName("This test needs to run against discovery service instance that has application/health endpoint authentication enabled.") void thenDoNotRequireAuthentication() { given() @@ -102,7 +101,6 @@ void thenDoNotRequireAuthentication() { } @Test - @TestsNotMeantForZowe("Automation needs unprotected health endpoint") @DisplayName("This test needs to run against discovery service instance that has application/health endpoint authentication enabled with authentication.") void thenDoNotAuthenticateTheRequest() { String token = SecurityUtils.gatewayToken(USERNAME, PASSWORD); diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java index 9646bfcc7b..8580dd5127 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java @@ -70,7 +70,6 @@ class GivenInvalidBearerAuthentication { class WhenAccessingProtectedEndpoint { @ParameterizedTest - @TestsNotMeantForZowe("Automation needs unprotected health endpoint") @ValueSource(strings = {ACTUATOR_ENDPOINT, HEALTH_ENDPOINT}) void thenReturnUnauthorized(String endpoint) { String expectedMessage = "The request has not been applied because it lacks valid authentication credentials."; From 12d95228355ff12f8410ea0e30541ffd760a89c5 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 10 Mar 2025 13:22:43 +0100 Subject: [PATCH 08/21] wip Signed-off-by: Pablo Carle --- .../discovery/DiscoveryServiceAuthenticationTest.java | 2 ++ .../apiml/functional/gateway/GatewayAuthenticationTest.java | 1 + 2 files changed, 3 insertions(+) diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java index d4823063d2..67b8d68787 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java @@ -90,6 +90,7 @@ void thenReturnUnauthorized() { } @Test + @TestsNotMeantForZowe("Automation needs unprotected health endpoint") @DisplayName("This test needs to run against discovery service instance that has application/health endpoint authentication enabled.") void thenDoNotRequireAuthentication() { given() @@ -101,6 +102,7 @@ void thenDoNotRequireAuthentication() { } @Test + @TestsNotMeantForZowe("Automation needs unprotected health endpoint") @DisplayName("This test needs to run against discovery service instance that has application/health endpoint authentication enabled with authentication.") void thenDoNotAuthenticateTheRequest() { String token = SecurityUtils.gatewayToken(USERNAME, PASSWORD); diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java index 8580dd5127..9646bfcc7b 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java @@ -70,6 +70,7 @@ class GivenInvalidBearerAuthentication { class WhenAccessingProtectedEndpoint { @ParameterizedTest + @TestsNotMeantForZowe("Automation needs unprotected health endpoint") @ValueSource(strings = {ACTUATOR_ENDPOINT, HEALTH_ENDPOINT}) void thenReturnUnauthorized(String endpoint) { String expectedMessage = "The request has not been applied because it lacks valid authentication credentials."; From fe8a8674cf7fea314bfe722501f0d2e428fc36d2 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 10 Mar 2025 13:51:25 +0100 Subject: [PATCH 09/21] rollback v3 specific changes Signed-off-by: Pablo Carle --- .../discovery/DiscoveryServiceAuthenticationTest.java | 7 +++---- .../functional/gateway/GatewayAuthenticationTest.java | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java index 67b8d68787..20b9ea6539 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/discovery/DiscoveryServiceAuthenticationTest.java @@ -12,10 +12,9 @@ import io.restassured.RestAssured; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.DisplayName; - import org.zowe.apiml.util.SecurityUtils; import org.zowe.apiml.util.categories.GeneralAuthenticationTest; import org.zowe.apiml.util.categories.TestsNotMeantForZowe; @@ -91,13 +90,13 @@ void thenReturnUnauthorized() { @Test @TestsNotMeantForZowe("Automation needs unprotected health endpoint") - @DisplayName("This test needs to run against discovery service instance that has application/health endpoint authentication enabled.") + @DisplayName("This test needs to run against discovery service instance that has application/health endpoint authentication disabled.") void thenDoNotRequireAuthentication() { given() .when() .get(DiscoveryUtils.getDiscoveryUrl() + DISCOVERY_HEALTH_ENDPOINT) .then() - .statusCode(is(SC_UNAUTHORIZED)); + .statusCode(is(SC_OK)); } diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java index 9646bfcc7b..f31243ed1f 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayAuthenticationTest.java @@ -73,7 +73,7 @@ class WhenAccessingProtectedEndpoint { @TestsNotMeantForZowe("Automation needs unprotected health endpoint") @ValueSource(strings = {ACTUATOR_ENDPOINT, HEALTH_ENDPOINT}) void thenReturnUnauthorized(String endpoint) { - String expectedMessage = "The request has not been applied because it lacks valid authentication credentials."; + String expectedMessage = "Token is not valid for URL '" + endpoint + "'"; // Gateway request to url given() .header("Authorization", "Bearer invalidToken") @@ -82,7 +82,7 @@ void thenReturnUnauthorized(String endpoint) { .then() .statusCode(is(SC_UNAUTHORIZED)) .body( - "messages.find { it.messageNumber == 'ZWEAO402E' }.messageContent", equalTo(expectedMessage) + "messages.find { it.messageNumber == 'ZWEAG130E' }.messageContent", equalTo(expectedMessage) ); } From 61a02479fd11b9b61396a739f632814f849feea8 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 10 Mar 2025 14:14:36 +0100 Subject: [PATCH 10/21] fix return code Signed-off-by: Pablo Carle --- .../java/org/zowe/apiml/integration/zaas/SafIdTokensTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/SafIdTokensTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/SafIdTokensTest.java index 2baa9395c0..e3d05f190e 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/SafIdTokensTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/zaas/SafIdTokensTest.java @@ -184,7 +184,7 @@ void givenInvalidApplicationName() { .when() .post(ZAAS_SAFIDT_URI) .then() - .statusCode(is(SC_BAD_REQUEST)) + .statusCode(is(SC_INTERNAL_SERVER_ERROR)) .body("messages.find { it.messageNumber == 'ZWEAG141E' }.messageContent", containsString(expectedMessage)); //@formatter:on } From b2d3392bbdbf030ac066eeff33bf200bbd2e4cb4 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 10 Mar 2025 14:57:48 +0100 Subject: [PATCH 11/21] assertion message Signed-off-by: Pablo Carle --- .../integration/authentication/pat/PATWithAllSchemesTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java index 0573a0daa2..20ce547dbb 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/PATWithAllSchemesTest.java @@ -70,7 +70,7 @@ static Stream schemas() { jwt = jwt.substring(jwt.indexOf("=") + 1, jwt.contains(";") ? jwt.indexOf(";") : jwt.length()); try { String issuer = JWTParser.parse(jwt).getJWTClaimsSet().toJSONObject().get("iss").toString(); - assertEquals("zOSMF", issuer); + assertEquals("zOSMF", issuer, "Issuer did not match. Response from Discoverable Client was: " + r.getBody().asPrettyString()); } catch (ParseException e) { fail(e); } From 63ce6076a8aca06dcfe7d47d3eaa1159ccc41782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jare=C5=A1?= Date: Mon, 10 Mar 2025 15:55:51 +0100 Subject: [PATCH 12/21] cherry-pick of changes from v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pavel Jareš --- .../client/services/AparBasedService.java | 2 -- .../services/apars/AuthenticateApar.java | 2 +- .../client/services/apars/FunctionalApar.java | 20 +++++++++++++++--- .../apiml/client/services/apars/PH12143.java | 21 +++++++++---------- .../apiml/client/services/apars/PH34201.java | 6 +++--- .../apiml/client/services/apars/PH34912.java | 2 +- .../apiml/client/services/apars/PHBase.java | 6 +++--- .../apiml/client/services/apars/RSU2012.java | 6 +++--- .../src/main/resources/application.yml | 4 ++++ .../client/services/AparBasedServiceTest.java | 6 +++--- .../client/services/apars/PH12143Test.java | 8 +++---- 11 files changed, 49 insertions(+), 34 deletions(-) diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/AparBasedService.java b/mock-services/src/main/java/org/zowe/apiml/client/services/AparBasedService.java index 2ca50ce558..ee0c32d580 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/AparBasedService.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/AparBasedService.java @@ -11,7 +11,6 @@ package org.zowe.apiml.client.services; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -33,7 +32,6 @@ public class AparBasedService { private final List appliedApars; private final Versions versions; - @Autowired public AparBasedService(@Value("${zosmf.baseVersion}") String baseVersion, @Value("${zosmf.appliedApars}") List appliedApars, Versions versions) { this.baseVersion = baseVersion; this.appliedApars = appliedApars; diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/AuthenticateApar.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/AuthenticateApar.java index 4ba2148141..8019cc5513 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/AuthenticateApar.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/AuthenticateApar.java @@ -47,6 +47,6 @@ protected ResponseEntity handleAuthenticationDefault(Map head } private boolean isUnauthorized(Map headers) { - return containsInvalidOrNoUser(headers) && noLtpaCookie(headers); + return containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers); } } diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/FunctionalApar.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/FunctionalApar.java index 7fdd0e2d5a..44398676c2 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/FunctionalApar.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/FunctionalApar.java @@ -13,6 +13,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.util.StringUtils; import org.zowe.apiml.client.model.LoginBody; import org.zowe.apiml.client.services.JwtTokenService; @@ -195,13 +196,13 @@ protected String[] getPiecesOfCredentials(Map headers) { throw new IllegalArgumentException("Headers did not have cookie or authorization field"); } - protected boolean noLtpaCookie(Map headers) { + protected boolean ltpaIsPresent(Map headers) { String cookie = getAuthCookie(headers); - return cookie == null || !cookie.contains(LTPA_TOKEN_NAME); + return cookie != null && cookie.contains(LTPA_TOKEN_NAME); } protected boolean validLtpaCookie(Map headers) { - if (noLtpaCookie(headers)) { + if (!ltpaIsPresent(headers)) { return false; } String token = jwtTokenService.extractLtpaToken(headers); @@ -218,6 +219,19 @@ protected boolean isValidJwtCookie(Map headers) { } + protected boolean isValidAuthHeader(String authHeader) { + if (!StringUtils.hasText(authHeader)) { + return false; + } + + if (authHeader.startsWith("Bearer")) { + String jwtToken = authHeader.length() > 8 ? authHeader.substring(7) : ""; + return jwtTokenService.validateJwtToken(jwtToken); + } + + return true; + } + private String getAuthCookie(Map headers) { return headers.get(COOKIE_HEADER) != null ? headers.get(COOKIE_HEADER) : headers.get(HttpHeaders.COOKIE); } diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH12143.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH12143.java index 0f80ae3a60..d87e46eaa2 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH12143.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH12143.java @@ -30,9 +30,9 @@ public PH12143(List usernames, List passwords, String keystorePa @Override protected ResponseEntity handleAuthenticationCreate(Map headers, HttpServletResponse response) { if (noAuthentication(headers)) { - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } - if (isUnauthorized(headers)) { + if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } @@ -42,15 +42,18 @@ protected ResponseEntity handleAuthenticationCreate(Map heade @Override protected ResponseEntity handleAuthenticationVerify(Map headers, HttpServletResponse response) { - return handleAuthenticationCreate(headers, response); + + if (containsInvalidOrNoUser(headers) && !isValidJwtCookie(headers) && !ltpaIsPresent(headers)) { + return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); + } + String[] credentials = getPiecesOfCredentials(headers); + return validJwtResponse(response, credentials[0], keystorePath); } @Override protected ResponseEntity handleAuthenticationDelete(Map headers) { - if (noAuthentication(headers)) { - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); - } - if (isValidJwtCookie(headers) || isUnauthorized(headers)) { + + if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers) && !isValidJwtCookie(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } return new ResponseEntity<>(HttpStatus.NO_CONTENT); @@ -71,8 +74,4 @@ protected ResponseEntity handleJwtKeys() { " ]\n" + "}", HttpStatus.OK); } - - private boolean isUnauthorized(Map headers) { - return containsInvalidOrNoUser(headers) && noLtpaCookie(headers); - } } diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34201.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34201.java index 5180195985..245bf3fb3d 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34201.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34201.java @@ -29,7 +29,7 @@ public PH34201(List usernames, List passwords, String keystorePa @Override protected ResponseEntity handleAuthenticationCreate(Map headers, HttpServletResponse response) { // JWT token not accepted for create method - if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers)) { + if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } @@ -39,7 +39,7 @@ protected ResponseEntity handleAuthenticationCreate(Map heade @Override protected ResponseEntity handleAuthenticationVerify(Map headers, HttpServletResponse response) { - if (containsInvalidOrNoUser(headers) && !isValidJwtCookie(headers) && noLtpaCookie(headers)) { + if (containsInvalidOrNoUser(headers) && !isValidJwtCookie(headers) && !ltpaIsPresent(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } @@ -49,7 +49,7 @@ protected ResponseEntity handleAuthenticationVerify(Map heade @Override protected ResponseEntity handleAuthenticationDelete(Map headers) { - if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers) && !isValidJwtCookie(headers)) { + if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers) && !isValidJwtCookie(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } return new ResponseEntity<>(HttpStatus.NO_CONTENT); diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34912.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34912.java index 42c75aad4d..2b45ee50a3 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34912.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34912.java @@ -75,7 +75,7 @@ protected ResponseEntity handleJwtKeys() { } private boolean isUnauthorized(Map headers) { - return containsInvalidOrNoUser(headers) && noLtpaCookie(headers); + return containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers); } private boolean isInternalError(LoginBody body) { diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PHBase.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PHBase.java index 65d5401848..7e3385e2a6 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PHBase.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PHBase.java @@ -34,7 +34,7 @@ protected ResponseEntity handleAuthenticationVerify(Map heade if (noAuthentication(headers)) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers)) { + if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } @@ -70,11 +70,11 @@ protected ResponseEntity handleFiles(Map headers) { String authorization = headers.get(AUTHORIZATION_HEADER); if (authorization != null) { - if (authorization.startsWith("Bearer")) { + if (!isValidAuthHeader(authorization) && !ltpaIsPresent(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } } else { - if (noLtpaCookie(headers) || !isValidJwtCookie(headers)) { + if (!isValidJwtCookie(headers) && !ltpaIsPresent(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } } diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/RSU2012.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/RSU2012.java index 1bca12a44d..0fe4fc06a5 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/RSU2012.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/RSU2012.java @@ -30,7 +30,7 @@ public RSU2012(List usernames, List passwords, String keystorePa @Override protected ResponseEntity handleAuthenticationCreate(Map headers, HttpServletResponse response) { // JWT token not accepted for create method - if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers)) { + if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers)) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } @@ -40,7 +40,7 @@ protected ResponseEntity handleAuthenticationCreate(Map heade @Override protected ResponseEntity handleAuthenticationVerify(Map headers, HttpServletResponse response) { - if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers) && !isValidJwtCookie(headers)) { + if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers) && !isValidJwtCookie(headers)) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } @@ -50,7 +50,7 @@ protected ResponseEntity handleAuthenticationVerify(Map heade @Override protected ResponseEntity handleAuthenticationDelete(Map headers) { - if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers) && !isValidJwtCookie(headers)) { + if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers) && !isValidJwtCookie(headers)) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } return new ResponseEntity<>(HttpStatus.NO_CONTENT); diff --git a/mock-services/src/main/resources/application.yml b/mock-services/src/main/resources/application.yml index bbfdee7b7e..3dbeaa4e10 100644 --- a/mock-services/src/main/resources/application.yml +++ b/mock-services/src/main/resources/application.yml @@ -1,3 +1,7 @@ +logging: + level: + ROOT: INFO + org.apache.tomcat.util.net.SSLUtilBase: ERROR spring: application: name: Mock services diff --git a/mock-services/src/test/java/org/zowe/apiml/client/services/AparBasedServiceTest.java b/mock-services/src/test/java/org/zowe/apiml/client/services/AparBasedServiceTest.java index bb22eac703..527e0a2235 100644 --- a/mock-services/src/test/java/org/zowe/apiml/client/services/AparBasedServiceTest.java +++ b/mock-services/src/test/java/org/zowe/apiml/client/services/AparBasedServiceTest.java @@ -64,7 +64,7 @@ void givenOneAparVersion_returnResultOfApply() { Optional> expectedResult = Optional.of(new ResponseEntity<>(HttpStatus.OK)); ResponseEntity expected = expectedResult.get(); when(versions.fullSetOfApplied(any(), any())).thenReturn(Collections.singletonList(apar)); - when(apar.apply(ArgumentMatchers.any())).thenReturn(expectedResult); + when(apar.apply(any(Object[].class))).thenReturn(expectedResult); ResponseEntity result = underTest.process(SERVICE, METHOD, response, HEADERS); assertThat(result, is(expected)); @@ -80,8 +80,8 @@ void givenTwoAparVersions_returnLastResultOfApply() { aparList.add(apar); aparList.add(apar2); when(versions.fullSetOfApplied(any(), any())).thenReturn(aparList); - when(apar.apply(ArgumentMatchers.any())).thenReturn(Optional.of(new ResponseEntity<>(HttpStatus.NO_CONTENT))); - when(apar2.apply(ArgumentMatchers.any())).thenReturn(expectedResult); + when(apar.apply(any(Object[].class))).thenReturn(Optional.of(new ResponseEntity<>(HttpStatus.NO_CONTENT))); + when(apar2.apply(any(Object[].class))).thenReturn(expectedResult); ResponseEntity result = underTest.process(SERVICE, METHOD, response, HEADERS); assertThat(result, is(expected)); diff --git a/mock-services/src/test/java/org/zowe/apiml/client/services/apars/PH12143Test.java b/mock-services/src/test/java/org/zowe/apiml/client/services/apars/PH12143Test.java index 42cebf92e2..0f8b2bea03 100644 --- a/mock-services/src/test/java/org/zowe/apiml/client/services/apars/PH12143Test.java +++ b/mock-services/src/test/java/org/zowe/apiml/client/services/apars/PH12143Test.java @@ -51,8 +51,8 @@ void setUp() { class whenAuthenticating { @ParameterizedTest @ValueSource(strings = {"create", "verify", "delete"}) - void givenNoAuthorization_thenReturnInternalServerError(String method) { - Optional> expected = Optional.of(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); + void givenNoAuthorization_thenReturnUnauthorized(String method) { + Optional> expected = Optional.of(new ResponseEntity<>(HttpStatus.UNAUTHORIZED)); Optional> result = underTest.apply(SERVICE, method, Optional.empty(), mockResponse, headers); @@ -61,8 +61,8 @@ void givenNoAuthorization_thenReturnInternalServerError(String method) { @ParameterizedTest @ValueSource(strings = {"create", "verify", "delete"}) - void givenEmptyAuthorization_thenReturnInternalServerError(String method) { - Optional> expected = Optional.of(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); + void givenEmptyAuthorization_thenReturnUnauthorized(String method) { + Optional> expected = Optional.of(new ResponseEntity<>(HttpStatus.UNAUTHORIZED)); headers.put("authorization", ""); Optional> result = underTest.apply(SERVICE, method, Optional.empty(), mockResponse, headers); From a5980ba3b804dedc3ce9a53f5e1c89445910f3cd Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 10 Mar 2025 16:07:34 +0100 Subject: [PATCH 13/21] Revert "cherry-pick of changes from v3" This reverts commit 63ce6076a8aca06dcfe7d47d3eaa1159ccc41782. --- .../client/services/AparBasedService.java | 2 ++ .../services/apars/AuthenticateApar.java | 2 +- .../client/services/apars/FunctionalApar.java | 20 +++--------------- .../apiml/client/services/apars/PH12143.java | 21 ++++++++++--------- .../apiml/client/services/apars/PH34201.java | 6 +++--- .../apiml/client/services/apars/PH34912.java | 2 +- .../apiml/client/services/apars/PHBase.java | 6 +++--- .../apiml/client/services/apars/RSU2012.java | 6 +++--- .../src/main/resources/application.yml | 4 ---- .../client/services/AparBasedServiceTest.java | 6 +++--- .../client/services/apars/PH12143Test.java | 8 +++---- 11 files changed, 34 insertions(+), 49 deletions(-) diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/AparBasedService.java b/mock-services/src/main/java/org/zowe/apiml/client/services/AparBasedService.java index ee0c32d580..2ca50ce558 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/AparBasedService.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/AparBasedService.java @@ -11,6 +11,7 @@ package org.zowe.apiml.client.services; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -32,6 +33,7 @@ public class AparBasedService { private final List appliedApars; private final Versions versions; + @Autowired public AparBasedService(@Value("${zosmf.baseVersion}") String baseVersion, @Value("${zosmf.appliedApars}") List appliedApars, Versions versions) { this.baseVersion = baseVersion; this.appliedApars = appliedApars; diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/AuthenticateApar.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/AuthenticateApar.java index 8019cc5513..4ba2148141 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/AuthenticateApar.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/AuthenticateApar.java @@ -47,6 +47,6 @@ protected ResponseEntity handleAuthenticationDefault(Map head } private boolean isUnauthorized(Map headers) { - return containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers); + return containsInvalidOrNoUser(headers) && noLtpaCookie(headers); } } diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/FunctionalApar.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/FunctionalApar.java index 44398676c2..7fdd0e2d5a 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/FunctionalApar.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/FunctionalApar.java @@ -13,7 +13,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.util.StringUtils; import org.zowe.apiml.client.model.LoginBody; import org.zowe.apiml.client.services.JwtTokenService; @@ -196,13 +195,13 @@ protected String[] getPiecesOfCredentials(Map headers) { throw new IllegalArgumentException("Headers did not have cookie or authorization field"); } - protected boolean ltpaIsPresent(Map headers) { + protected boolean noLtpaCookie(Map headers) { String cookie = getAuthCookie(headers); - return cookie != null && cookie.contains(LTPA_TOKEN_NAME); + return cookie == null || !cookie.contains(LTPA_TOKEN_NAME); } protected boolean validLtpaCookie(Map headers) { - if (!ltpaIsPresent(headers)) { + if (noLtpaCookie(headers)) { return false; } String token = jwtTokenService.extractLtpaToken(headers); @@ -219,19 +218,6 @@ protected boolean isValidJwtCookie(Map headers) { } - protected boolean isValidAuthHeader(String authHeader) { - if (!StringUtils.hasText(authHeader)) { - return false; - } - - if (authHeader.startsWith("Bearer")) { - String jwtToken = authHeader.length() > 8 ? authHeader.substring(7) : ""; - return jwtTokenService.validateJwtToken(jwtToken); - } - - return true; - } - private String getAuthCookie(Map headers) { return headers.get(COOKIE_HEADER) != null ? headers.get(COOKIE_HEADER) : headers.get(HttpHeaders.COOKIE); } diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH12143.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH12143.java index d87e46eaa2..0f80ae3a60 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH12143.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH12143.java @@ -30,9 +30,9 @@ public PH12143(List usernames, List passwords, String keystorePa @Override protected ResponseEntity handleAuthenticationCreate(Map headers, HttpServletResponse response) { if (noAuthentication(headers)) { - return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers)) { + if (isUnauthorized(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } @@ -42,18 +42,15 @@ protected ResponseEntity handleAuthenticationCreate(Map heade @Override protected ResponseEntity handleAuthenticationVerify(Map headers, HttpServletResponse response) { - - if (containsInvalidOrNoUser(headers) && !isValidJwtCookie(headers) && !ltpaIsPresent(headers)) { - return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); - } - String[] credentials = getPiecesOfCredentials(headers); - return validJwtResponse(response, credentials[0], keystorePath); + return handleAuthenticationCreate(headers, response); } @Override protected ResponseEntity handleAuthenticationDelete(Map headers) { - - if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers) && !isValidJwtCookie(headers)) { + if (noAuthentication(headers)) { + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + if (isValidJwtCookie(headers) || isUnauthorized(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } return new ResponseEntity<>(HttpStatus.NO_CONTENT); @@ -74,4 +71,8 @@ protected ResponseEntity handleJwtKeys() { " ]\n" + "}", HttpStatus.OK); } + + private boolean isUnauthorized(Map headers) { + return containsInvalidOrNoUser(headers) && noLtpaCookie(headers); + } } diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34201.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34201.java index 245bf3fb3d..5180195985 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34201.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34201.java @@ -29,7 +29,7 @@ public PH34201(List usernames, List passwords, String keystorePa @Override protected ResponseEntity handleAuthenticationCreate(Map headers, HttpServletResponse response) { // JWT token not accepted for create method - if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers)) { + if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } @@ -39,7 +39,7 @@ protected ResponseEntity handleAuthenticationCreate(Map heade @Override protected ResponseEntity handleAuthenticationVerify(Map headers, HttpServletResponse response) { - if (containsInvalidOrNoUser(headers) && !isValidJwtCookie(headers) && !ltpaIsPresent(headers)) { + if (containsInvalidOrNoUser(headers) && !isValidJwtCookie(headers) && noLtpaCookie(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } @@ -49,7 +49,7 @@ protected ResponseEntity handleAuthenticationVerify(Map heade @Override protected ResponseEntity handleAuthenticationDelete(Map headers) { - if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers) && !isValidJwtCookie(headers)) { + if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers) && !isValidJwtCookie(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } return new ResponseEntity<>(HttpStatus.NO_CONTENT); diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34912.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34912.java index 2b45ee50a3..42c75aad4d 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34912.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PH34912.java @@ -75,7 +75,7 @@ protected ResponseEntity handleJwtKeys() { } private boolean isUnauthorized(Map headers) { - return containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers); + return containsInvalidOrNoUser(headers) && noLtpaCookie(headers); } private boolean isInternalError(LoginBody body) { diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PHBase.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PHBase.java index 7e3385e2a6..65d5401848 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PHBase.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/PHBase.java @@ -34,7 +34,7 @@ protected ResponseEntity handleAuthenticationVerify(Map heade if (noAuthentication(headers)) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers)) { + if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } @@ -70,11 +70,11 @@ protected ResponseEntity handleFiles(Map headers) { String authorization = headers.get(AUTHORIZATION_HEADER); if (authorization != null) { - if (!isValidAuthHeader(authorization) && !ltpaIsPresent(headers)) { + if (authorization.startsWith("Bearer")) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } } else { - if (!isValidJwtCookie(headers) && !ltpaIsPresent(headers)) { + if (noLtpaCookie(headers) || !isValidJwtCookie(headers)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } } diff --git a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/RSU2012.java b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/RSU2012.java index 0fe4fc06a5..1bca12a44d 100644 --- a/mock-services/src/main/java/org/zowe/apiml/client/services/apars/RSU2012.java +++ b/mock-services/src/main/java/org/zowe/apiml/client/services/apars/RSU2012.java @@ -30,7 +30,7 @@ public RSU2012(List usernames, List passwords, String keystorePa @Override protected ResponseEntity handleAuthenticationCreate(Map headers, HttpServletResponse response) { // JWT token not accepted for create method - if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers)) { + if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers)) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } @@ -40,7 +40,7 @@ protected ResponseEntity handleAuthenticationCreate(Map heade @Override protected ResponseEntity handleAuthenticationVerify(Map headers, HttpServletResponse response) { - if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers) && !isValidJwtCookie(headers)) { + if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers) && !isValidJwtCookie(headers)) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } @@ -50,7 +50,7 @@ protected ResponseEntity handleAuthenticationVerify(Map heade @Override protected ResponseEntity handleAuthenticationDelete(Map headers) { - if (containsInvalidOrNoUser(headers) && !ltpaIsPresent(headers) && !isValidJwtCookie(headers)) { + if (containsInvalidOrNoUser(headers) && noLtpaCookie(headers) && !isValidJwtCookie(headers)) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } return new ResponseEntity<>(HttpStatus.NO_CONTENT); diff --git a/mock-services/src/main/resources/application.yml b/mock-services/src/main/resources/application.yml index 3dbeaa4e10..bbfdee7b7e 100644 --- a/mock-services/src/main/resources/application.yml +++ b/mock-services/src/main/resources/application.yml @@ -1,7 +1,3 @@ -logging: - level: - ROOT: INFO - org.apache.tomcat.util.net.SSLUtilBase: ERROR spring: application: name: Mock services diff --git a/mock-services/src/test/java/org/zowe/apiml/client/services/AparBasedServiceTest.java b/mock-services/src/test/java/org/zowe/apiml/client/services/AparBasedServiceTest.java index 527e0a2235..bb22eac703 100644 --- a/mock-services/src/test/java/org/zowe/apiml/client/services/AparBasedServiceTest.java +++ b/mock-services/src/test/java/org/zowe/apiml/client/services/AparBasedServiceTest.java @@ -64,7 +64,7 @@ void givenOneAparVersion_returnResultOfApply() { Optional> expectedResult = Optional.of(new ResponseEntity<>(HttpStatus.OK)); ResponseEntity expected = expectedResult.get(); when(versions.fullSetOfApplied(any(), any())).thenReturn(Collections.singletonList(apar)); - when(apar.apply(any(Object[].class))).thenReturn(expectedResult); + when(apar.apply(ArgumentMatchers.any())).thenReturn(expectedResult); ResponseEntity result = underTest.process(SERVICE, METHOD, response, HEADERS); assertThat(result, is(expected)); @@ -80,8 +80,8 @@ void givenTwoAparVersions_returnLastResultOfApply() { aparList.add(apar); aparList.add(apar2); when(versions.fullSetOfApplied(any(), any())).thenReturn(aparList); - when(apar.apply(any(Object[].class))).thenReturn(Optional.of(new ResponseEntity<>(HttpStatus.NO_CONTENT))); - when(apar2.apply(any(Object[].class))).thenReturn(expectedResult); + when(apar.apply(ArgumentMatchers.any())).thenReturn(Optional.of(new ResponseEntity<>(HttpStatus.NO_CONTENT))); + when(apar2.apply(ArgumentMatchers.any())).thenReturn(expectedResult); ResponseEntity result = underTest.process(SERVICE, METHOD, response, HEADERS); assertThat(result, is(expected)); diff --git a/mock-services/src/test/java/org/zowe/apiml/client/services/apars/PH12143Test.java b/mock-services/src/test/java/org/zowe/apiml/client/services/apars/PH12143Test.java index 0f8b2bea03..42cebf92e2 100644 --- a/mock-services/src/test/java/org/zowe/apiml/client/services/apars/PH12143Test.java +++ b/mock-services/src/test/java/org/zowe/apiml/client/services/apars/PH12143Test.java @@ -51,8 +51,8 @@ void setUp() { class whenAuthenticating { @ParameterizedTest @ValueSource(strings = {"create", "verify", "delete"}) - void givenNoAuthorization_thenReturnUnauthorized(String method) { - Optional> expected = Optional.of(new ResponseEntity<>(HttpStatus.UNAUTHORIZED)); + void givenNoAuthorization_thenReturnInternalServerError(String method) { + Optional> expected = Optional.of(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); Optional> result = underTest.apply(SERVICE, method, Optional.empty(), mockResponse, headers); @@ -61,8 +61,8 @@ void givenNoAuthorization_thenReturnUnauthorized(String method) { @ParameterizedTest @ValueSource(strings = {"create", "verify", "delete"}) - void givenEmptyAuthorization_thenReturnUnauthorized(String method) { - Optional> expected = Optional.of(new ResponseEntity<>(HttpStatus.UNAUTHORIZED)); + void givenEmptyAuthorization_thenReturnInternalServerError(String method) { + Optional> expected = Optional.of(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); headers.put("authorization", ""); Optional> result = underTest.apply(SERVICE, method, Optional.empty(), mockResponse, headers); From d2ca941dc8b5ae17534c0fd4744039d1c0852d52 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 10 Mar 2025 16:28:22 +0100 Subject: [PATCH 14/21] remove applied lpar in infinispan Signed-off-by: Pablo Carle --- .github/workflows/integration-tests.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index eb4b4f15ee..d7a616a49a 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -1352,8 +1352,6 @@ jobs: image: ghcr.io/balhar-jakub/gateway-service:${{ github.run_id }}-${{ github.run_number }} mock-services: image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }} - env: - ZOSMF_APPLIEDAPARS: AuthenticateApar steps: - uses: actions/checkout@v4 From eb864f2a2b8940a8304fa1f82eb4c225b863ab9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jare=C5=A1?= Date: Mon, 10 Mar 2025 16:56:40 +0100 Subject: [PATCH 15/21] fix log messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pavel Jareš --- .../service/schema/source/PATAuthSourceService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/security/service/schema/source/PATAuthSourceService.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/security/service/schema/source/PATAuthSourceService.java index ffa03189c0..0366bdd471 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/security/service/schema/source/PATAuthSourceService.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/security/service/schema/source/PATAuthSourceService.java @@ -91,12 +91,12 @@ public boolean isValid(AuthSource authSource) { serviceId = ((PATAuthSource) authSource).getDefaultServiceId(); } boolean validForScopes = tokenProvider.isValidForScopes(token, serviceId); - logger.log(MessageType.DEBUG, "PAT is %s for scope: %s ", validForScopes ? "valid" : "not valid", serviceId); + logger.log(MessageType.DEBUG, "PAT is {} for scope: {} ", validForScopes ? "valid" : "not valid", serviceId); boolean invalidate = tokenProvider.isInvalidated(token); - logger.log(MessageType.DEBUG, "PAT was %s", invalidate ? "invalidated" : "not invalidated"); + logger.log(MessageType.DEBUG, "PAT was {}", invalidate ? "invalidated" : "not invalidated"); return validForScopes && !invalidate; } catch (Exception e) { - logger.log(MessageType.ERROR, "PAT is not valid due to the exception: %s", e.getMessage()); + logger.log(MessageType.ERROR, "PAT is not valid due to the exception: {}", e.getMessage()); return false; } } From 20010ff61d6a4d4336cc7f3ef03ace20a7d562de Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 10 Mar 2025 17:07:23 +0100 Subject: [PATCH 16/21] add debug logs to PATs Signed-off-by: Pablo Carle --- .../java/org/zowe/apiml/gateway/controllers/AuthController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/controllers/AuthController.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/controllers/AuthController.java index 577b4fcf3f..2ca8a579ca 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/controllers/AuthController.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/controllers/AuthController.java @@ -125,6 +125,7 @@ public ResponseEntity revokeAllUserAccessTokens(@RequestBody(required = return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); } String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString(); + log.debug("revokeAllUserAccessTokens: userId={}", userId); long timeStamp = 0; if (rulesRequestModel != null) { timeStamp = rulesRequestModel.getTimestamp(); @@ -143,6 +144,7 @@ public ResponseEntity revokeAccessTokensForUser(@RequestBody() RulesRequ if (userId == null) { return badRequestForPATInvalidation(); } + log.debug("revokeAccessTokensForUser: userId={}", userId); tokenProvider.invalidateAllTokensForUser(userId, timeStamp); return new ResponseEntity<>(HttpStatus.NO_CONTENT); From 738c6433610124830f1ebe6f3436df97e802c811 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 11 Mar 2025 08:52:38 +0100 Subject: [PATCH 17/21] fix unit test Signed-off-by: Pablo Carle --- .../security/service/ticket/SuccessfulTicketHandlerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/security/service/ticket/SuccessfulTicketHandlerTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/security/service/ticket/SuccessfulTicketHandlerTest.java index 2adb2b83b5..87c7c1b585 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/security/service/ticket/SuccessfulTicketHandlerTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/security/service/ticket/SuccessfulTicketHandlerTest.java @@ -89,7 +89,7 @@ void shouldFailWhenGenerationFails() throws JsonProcessingException, Unsupported successfulTicketHandlerHandler.onAuthenticationSuccess(httpServletRequest, httpServletResponse, tokenAuthentication); assertEquals(MediaType.APPLICATION_JSON_VALUE, httpServletResponse.getContentType()); - assertEquals(HttpStatus.BAD_REQUEST.value(), httpServletResponse.getStatus()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), httpServletResponse.getStatus()); assertTrue(httpServletResponse.getContentAsString().contains("ZWEAG141E")); assertTrue(httpServletResponse.isCommitted()); } From 8b434cdb9cb7799a952ac97d6cd4d69dc1e931ee Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 11 Mar 2025 15:25:37 +0100 Subject: [PATCH 18/21] wip fixes for caching service Signed-off-by: Pablo Carle --- .../gateway/security/config/NewSecurityConfiguration.java | 2 -- .../security/service/token/ApimlAccessTokenProvider.java | 6 +++--- .../authentication/pat/AccessTokenServiceTest.java | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/NewSecurityConfiguration.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/NewSecurityConfiguration.java index 98e61e7931..2d71aed7fb 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/NewSecurityConfiguration.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/NewSecurityConfiguration.java @@ -267,7 +267,6 @@ public SecurityFilterChain authProtectedEndpointsFilterChain(HttpSecurity http) ))) .authorizeRequests(requests -> requests .anyRequest().authenticated()) - .x509(x509 -> x509.userDetailsService(x509UserDetailsService())) .authenticationProvider(compoundAuthProvider) // for authenticating credentials .apply(new CustomSecurityFilters()); return http.build(); @@ -314,7 +313,6 @@ public SecurityFilterChain authZaasEndpointsFilterChain(HttpSecurity http) throw ))) .authorizeRequests(requests -> requests .anyRequest().authenticated()) - .x509(x509 -> x509.userDetailsService(x509UserDetailsService())) .addFilterAfter(new CategorizeCertsFilter(publicKeyCertificatesBase64, certificateValidator), org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter.class) .addFilterAfter(new ExtractAuthSourceFilter(authSourceService, authExceptionHandler), org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter.class) .addFilterAfter(new ZaasAuthenticationFilter(authSourceService, authExceptionHandler), CategorizeCertsFilter.class); diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/security/service/token/ApimlAccessTokenProvider.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/security/service/token/ApimlAccessTokenProvider.java index 0027218614..a10561d3f6 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/security/service/token/ApimlAccessTokenProvider.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/security/service/token/ApimlAccessTokenProvider.java @@ -64,7 +64,7 @@ public void invalidateToken(String token) throws CachingServiceClientException, } public void invalidateAllTokensForUser(String userId, long timestamp) throws CachingServiceClientException { - String hashedUserId = getHash(userId); + String hashedUserId = getHash(userId.trim().toUpperCase()); if (timestamp == 0) { timestamp = System.currentTimeMillis(); } @@ -72,7 +72,7 @@ public void invalidateAllTokensForUser(String userId, long timestamp) throws Cac } public void invalidateAllTokensForService(String serviceId, long timestamp) throws CachingServiceClientException { - String hashedServiceId = getHash(serviceId); + String hashedServiceId = getHash(serviceId.trim().toLowerCase()); if (timestamp == 0) { timestamp = System.currentTimeMillis(); } @@ -82,7 +82,7 @@ public void invalidateAllTokensForService(String serviceId, long timestamp) thro public boolean isInvalidated(String token) throws CachingServiceClientException { QueryResponse parsedToken = authenticationService.parseJwtWithSignature(token); String hashedToken = getHash(token); - String hashedUserId = getHash(parsedToken.getUserId()); + String hashedUserId = getHash(parsedToken.getUserId().trim().toUpperCase()); List hashedServiceIds = parsedToken.getScopes().stream().map(this::getHash).collect(Collectors.toList()); Map> cacheMap = cachingServiceClient.readAllMaps(); diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java index f8cc967ac6..e0572e5617 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java @@ -14,7 +14,6 @@ import io.restassured.http.ContentType; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.zowe.apiml.util.SecurityUtils; @@ -290,7 +289,6 @@ void givenAuthorizedRequest_thenEvictRules() { } @Test - @Disabled("Disable for now; fix is in progress") void givenNotAuthorizedCall_thenDontAllowToRevokeTokensForUser() { String pat = SecurityUtils.personalAccessTokenWithClientCert(SslContext.clientCertValid); bodyContent = new ValidateRequestModel(); From f89510c37e6c5e731c9e68b28a2b84a3a9ca5a74 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 11 Mar 2025 15:32:29 +0100 Subject: [PATCH 19/21] wip fix test Signed-off-by: Pablo Carle --- .../integration/authentication/pat/AccessTokenServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java index e0572e5617..7c36d8c797 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java @@ -320,7 +320,7 @@ void givenNotAuthorizedCall_thenDontAllowToRevokeTokensForUser() { .when() .delete(REVOKE_FOR_USER_ENDPOINT) .then() - .statusCode(403); + .statusCode(401); } } From 9949c79b3347abc1f58d556f72d1bb932eb2c553 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 11 Mar 2025 16:02:15 +0100 Subject: [PATCH 20/21] fix unit test Signed-off-by: Pablo Carle --- .../security/service/token/ApimlAccessTokenProviderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/security/service/token/ApimlAccessTokenProviderTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/security/service/token/ApimlAccessTokenProviderTest.java index 32c7a107b2..1a0659433d 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/security/service/token/ApimlAccessTokenProviderTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/security/service/token/ApimlAccessTokenProviderTest.java @@ -142,7 +142,7 @@ void givenDifferentToken_returnNotInvalidated() throws Exception { @Test void givenTokenWithUserIdMatchingRule_returnInvalidated() { - String userId = accessTokenProvider.getHash("user"); + String userId = accessTokenProvider.getHash("USER"); when(as.parseJwtWithSignature(TOKEN_WITHOUT_SCOPES)).thenReturn(queryResponseWithoutScopes); Map invalidUsers = new HashMap<>(); From 46b02cd204a270f7e2cd5d36ed0e10cfc657886e Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Wed, 12 Mar 2025 17:02:52 +0100 Subject: [PATCH 21/21] wip Signed-off-by: Pablo Carle --- .../apiml/gateway/security/config/NewSecurityConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/NewSecurityConfiguration.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/NewSecurityConfiguration.java index 2d71aed7fb..8813d7f5f1 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/NewSecurityConfiguration.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/NewSecurityConfiguration.java @@ -313,6 +313,7 @@ public SecurityFilterChain authZaasEndpointsFilterChain(HttpSecurity http) throw ))) .authorizeRequests(requests -> requests .anyRequest().authenticated()) + .x509(x509 -> x509.userDetailsService(x509UserDetailsService())) .addFilterAfter(new CategorizeCertsFilter(publicKeyCertificatesBase64, certificateValidator), org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter.class) .addFilterAfter(new ExtractAuthSourceFilter(authSourceService, authExceptionHandler), org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter.class) .addFilterAfter(new ZaasAuthenticationFilter(authSourceService, authExceptionHandler), CategorizeCertsFilter.class);