Skip to content

Commit

Permalink
draft of fixes (except evaluation of client certificate in the ZAAS)
Browse files Browse the repository at this point in the history
Signed-off-by: Pavel Jareš <[email protected]>
  • Loading branch information
pj892031 committed Oct 25, 2024
1 parent 19ece5e commit 2c5b153
Show file tree
Hide file tree
Showing 19 changed files with 467 additions and 465 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.zowe.apiml.product.compatibility.ApimlErrorController;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.http.HttpServletRequest;
Expand Down

This file was deleted.

12 changes: 12 additions & 0 deletions config/local/mock-services.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
zosmf:
timeout: 1800

server:
ssl:
keyAlias: localhost
keyPassword: password
keyStore: keystore/localhost/localhost.keystore.p12
keyStorePassword: password
keyStoreType: PKCS12
trustStore: keystore/localhost/localhost.truststore.p12
trustStorePassword: password
trustStoreType: PKCS12

6 changes: 0 additions & 6 deletions config/local/zaas-service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@ spring:
enabled: always

server:
internal:
enabled: true
port: 10017
ssl:
keyAlias: localhost-multi
keyStore: keystore/localhost/localhost-multi.keystore.p12
ssl:
keyAlias: localhost
keyPassword: password
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static org.apache.hc.core5.http.HttpStatus.SC_OK;
Expand Down Expand Up @@ -172,14 +173,14 @@ private Mono<AuthorizationResponse<R>> requestWithHa(
Function<ServiceInstance, WebClient.RequestHeadersSpec<?>> requestCreator
) {
return requestCreator.apply(serviceInstanceIterator.next())
.exchangeToMono(clientResp -> switch (clientResp.statusCode().value()) {
case SC_UNAUTHORIZED -> Mono.just(new AuthorizationResponse<R>(clientResp.headers(), null));
case SC_OK -> clientResp.bodyToMono(getResponseClass()).map(b -> new AuthorizationResponse<R>(clientResp.headers(), b));
default -> Mono.empty();
})
.switchIfEmpty(serviceInstanceIterator.hasNext() ?
requestWithHa(serviceInstanceIterator, requestCreator) : Mono.empty()
);
.exchangeToMono(clientResp -> {
Supplier<Mono<AuthorizationResponse<R>>> unauthorized = () -> clientResp.bodyToMono(getResponseClass()).map(b -> new AuthorizationResponse<>(clientResp.headers(), b));
return switch (clientResp.statusCode().value()) {
case SC_UNAUTHORIZED -> Mono.just(new AuthorizationResponse<R>(clientResp.headers(), null));
case SC_OK -> unauthorized.get();
default -> serviceInstanceIterator.hasNext() ? requestWithHa(serviceInstanceIterator, requestCreator) : unauthorized.get();
};
});
}

protected Mono<Void> invoke(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

package org.zowe.apiml.gateway.service.scheme;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.gateway.filter.FilterDefinition;
Expand All @@ -18,6 +19,7 @@
import org.zowe.apiml.auth.Authentication;
import org.zowe.apiml.auth.AuthenticationScheme;

@Slf4j
@Component
public class HttpBasicPassticket implements SchemeHandler {

Expand All @@ -28,6 +30,11 @@ public AuthenticationScheme getAuthenticationScheme() {

@Override
public void apply(ServiceInstance serviceInstance, RouteDefinition routeDefinition, Authentication auth) {
if (StringUtils.isEmpty(auth.getApplid())) {
log.warn("Service {} does not have configured APPLID. The authorization scheme will be ignored", serviceInstance.getServiceId());
return;
}

FilterDefinition filterDef = new FilterDefinition();
filterDef.setName("PassticketFilterFactory");
filterDef.addArg("applicationName", auth.getApplid());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@

package org.zowe.apiml.gateway.acceptance;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.http.HttpHeaders;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.zowe.apiml.auth.AuthenticationScheme;
import org.zowe.apiml.gateway.acceptance.common.AcceptanceTest;
import org.zowe.apiml.gateway.acceptance.common.AcceptanceTestWithMockServices;
Expand All @@ -27,7 +31,9 @@

import static io.restassured.RestAssured.given;
import static org.apache.http.HttpStatus.SC_OK;
import static org.apache.http.HttpStatus.SC_UNAUTHORIZED;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

@AcceptanceTest
public class PassticketTest extends AcceptanceTestWithMockServices {
Expand All @@ -38,24 +44,24 @@ public class PassticketTest extends AcceptanceTestWithMockServices {
private static final String JWT = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiaWF0IjoxNjcxNDYxNjIzLCJleHAiOjE2NzE0OTA0MjMsImlzcyI6IkFQSU1MIiwianRpIjoiYmFlMTkyZTYtYTYxMi00MThhLWI2ZGMtN2I0NWI5NzM4ODI3IiwiZG9tIjoiRHVtbXkgcHJvdmlkZXIifQ.Vt5UjJUlbmuzmmEIodAACtj_AOxlsWqkFrFyWh4_MQRRPCj_zMIwnzpqRN-NJvKtUg1zxOCzXv2ypYNsglrXc7cH9wU3leK1gjYxK7IJjn2SBEb0dUL5m7-h4tFq2zNhcGH2GOmTpE2gTQGSTvDIdja-TIj_lAvUtbkiorm1RqrNu2MGC0WfgOGiak3tj2tNJLv_Y1ZMxNjzyHgXBMuNPozQrd4Vtnew3x4yy85LrTYF7jJM3U-e3AD2yImftxwycQvbkjNb-lWadejTVH0MgHMr04wVdDd8Nq5q7yrZf7YPzhias8ehNbew5CHiKut9SseZ1sO2WwgfhpEfsN4okg";
private static final String PASSTICKET = "ZOWE_DUMMY_PASS_TICKET";

@BeforeEach
void setup() throws IOException {
TicketResponse response = new TicketResponse();
response.setToken(JWT);
response.setUserId(USER_ID);
response.setApplicationName("IZUDFLT");
response.setTicket(PASSTICKET);
@Nested
class GivenValidAuthentication {

mockService("zaas").scope(MockService.Scope.CLASS)
.addEndpoint("/zaas/scheme/ticket")
@BeforeEach
void setup() throws IOException {
TicketResponse response = new TicketResponse();
response.setToken(JWT);
response.setUserId(USER_ID);
response.setApplicationName("IZUDFLT");
response.setTicket(PASSTICKET);

mockService("zaas").scope(MockService.Scope.CLASS)
.addEndpoint("/zaas/scheme/ticket")
.assertion(he -> assertEquals(SERVICE_ID, he.getRequestHeaders().getFirst("X-Service-Id")))
.assertion(he -> assertEquals(COOKIE_NAME + "=" + JWT, he.getRequestHeaders().getFirst("Cookie")))
.bodyJson(response)
.and().start();
}

@Nested
class GivenValidAuthentication {
.and().start();
}

@Test
void whenRequestingPassticketForAllowedAPPLID_thenTranslate() throws IOException {
Expand All @@ -78,4 +84,44 @@ void whenRequestingPassticketForAllowedAPPLID_thenTranslate() throws IOException

}

@Nested
class GivenInvalidAuthentication {

@ParameterizedTest
@ValueSource(ints = { 400, 401, 403, 404, 405, 500 })
void whenCannotGeneratePassticket_thenIgnoreTransformation(int responseCode) throws IOException {
mockService("zaas").scope(MockService.Scope.TEST)
.addEndpoint("/zaas/scheme/ticket")
.responseCode(responseCode)
.and().start();

var mockService = mockService(SERVICE_ID).scope(MockService.Scope.TEST)
.authenticationScheme(AuthenticationScheme.HTTP_BASIC_PASSTICKET).applid("IZUDFLT")
.addEndpoint("/" + SERVICE_ID + "/test")
.responseCode(401)
.bodyJson(new ResponseDto("ok"))
.assertion(he -> assertFalse(he.getRequestHeaders().containsKey(HttpHeaders.AUTHORIZATION)))
.and().start();

given()
.cookie(COOKIE_NAME, JWT)
.when()
.get(basePath + "/" + SERVICE_ID + "/api/v1/test")
.then()
.statusCode(Matchers.is(SC_UNAUTHORIZED))
.body("status", Matchers.is("ok"));

assertEquals(1, mockService.getEndpoint().getCounter());
}

}

@Data
@AllArgsConstructor
static class ResponseDto {

private String status;

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.zowe.apiml.auth.AuthenticationScheme;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;

Expand All @@ -44,4 +45,18 @@ void givenRouteDefinition_whenApply_thenFulfillFilterFactorArgs() {
assertEquals("PassticketFilterFactory", filterDefinition.getName());
}

@Test
void givenNoApplid_whenApply_thenSkipConfiguration() {
RouteDefinition routeDefinition = new RouteDefinition();
new HttpBasicPassticket().apply(mock(ServiceInstance.class), routeDefinition, new Authentication(AuthenticationScheme.HTTP_BASIC_PASSTICKET, null));
assertTrue(routeDefinition.getFilters().isEmpty());
}

@Test
void givenEmptyApplid_whenApply_thenSkipConfiguration() {
RouteDefinition routeDefinition = new RouteDefinition();
new HttpBasicPassticket().apply(mock(ServiceInstance.class), routeDefinition, new Authentication(AuthenticationScheme.HTTP_BASIC_PASSTICKET, ""));
assertTrue(routeDefinition.getFilters().isEmpty());
}

}

This file was deleted.

Loading

0 comments on commit 2c5b153

Please sign in to comment.