diff --git a/apiml/src/main/java/org/zowe/apiml/filter/BasicLoginFilter.java b/apiml/src/main/java/org/zowe/apiml/filter/BasicLoginFilter.java index 82ba534c12..ad9470a1fc 100644 --- a/apiml/src/main/java/org/zowe/apiml/filter/BasicLoginFilter.java +++ b/apiml/src/main/java/org/zowe/apiml/filter/BasicLoginFilter.java @@ -25,6 +25,7 @@ import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import org.zowe.apiml.handler.FailedAuthenticationWebHandler; +import org.zowe.apiml.product.opentelemetry.OtelRequestContext; import org.zowe.apiml.security.common.login.LoginFilter; import org.zowe.apiml.security.common.login.LoginRequest; import org.zowe.apiml.zaas.security.config.CompoundAuthProvider; @@ -50,7 +51,7 @@ * * *

This filter is intended to be used on /login endpoints.

- * + *

* Caution: Filter will read the body and make it available as a request attribute * * @see LoginRequest @@ -72,6 +73,8 @@ public BasicLoginFilter(CompoundAuthProvider compoundAuthProvider, FailedAuthent @Override public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { var hasBody = Optional.ofNullable(exchange.getAttribute(CachedBodyFilter.CACHED_BODY_ATTR)).isPresent(); + var otelContext = OtelRequestContext.of(exchange); + otelContext.authMethod(OtelRequestContext.BASIC_AUTH_TYPE); exchange.getAttributes().put(X509AuthFilter.SKIP_X509_AUTH_ATTR, hasBody); return extractBasicAuth(exchange) .map(this::useCredentials) diff --git a/apiml/src/main/java/org/zowe/apiml/handler/FailedAuthenticationWebHandler.java b/apiml/src/main/java/org/zowe/apiml/handler/FailedAuthenticationWebHandler.java index 2e20cd68b3..28ab96a943 100644 --- a/apiml/src/main/java/org/zowe/apiml/handler/FailedAuthenticationWebHandler.java +++ b/apiml/src/main/java/org/zowe/apiml/handler/FailedAuthenticationWebHandler.java @@ -26,6 +26,7 @@ import org.zowe.apiml.message.api.ApiMessageView; import org.zowe.apiml.message.log.ApimlLogger; import org.zowe.apiml.product.logging.annotations.InjectApimlLogger; +import org.zowe.apiml.product.opentelemetry.OtelRequestContext; import org.zowe.apiml.security.common.error.AuthExceptionHandler; import reactor.core.publisher.Mono; @@ -48,11 +49,15 @@ public class FailedAuthenticationWebHandler implements ServerAuthenticationFailu public Mono onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException exception) { var exchange = webFilterExchange.getExchange(); var requestUri = exchange.getRequest().getURI().getPath(); + var otelContext = OtelRequestContext.of(exchange); log.debug("Unauthorized access to '{}' endpoint", requestUri); + otelContext.authenticationFailed(); + otelContext.authErrorMessage(exception.getMessage()); var bufferFactory = new DefaultDataBufferFactory(); AtomicReference buffer = new AtomicReference<>(); BiConsumer consumer = (message, status) -> { exchange.getResponse().setStatusCode(status); + otelContext.authErrorType(status.getReasonPhrase()); if (message != null) { exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON); try { @@ -64,7 +69,7 @@ public Mono onAuthenticationFailure(WebFilterExchange webFilterExchange, A buffer.set(bufferFactory.wrap(new byte[0])); } }; - var addHeader = (BiConsumer)(name, value) -> exchange.getResponse().getHeaders().add(name, value); + var addHeader = (BiConsumer) (name, value) -> exchange.getResponse().getHeaders().add(name, value); try { handler.handleException(requestUri, consumer, addHeader, exception); } catch (ServletException e) { diff --git a/apiml/src/test/java/org/zowe/apiml/acceptance/OpenTelemetryResourceAttributesZosTest.java b/apiml/src/test/java/org/zowe/apiml/acceptance/OpenTelemetryResourceAttributesZosTest.java index f2f67eff38..8881f4ff62 100644 --- a/apiml/src/test/java/org/zowe/apiml/acceptance/OpenTelemetryResourceAttributesZosTest.java +++ b/apiml/src/test/java/org/zowe/apiml/acceptance/OpenTelemetryResourceAttributesZosTest.java @@ -69,7 +69,7 @@ private boolean assertAttributesBase(Attributes attributes, int port) { @Nested @AcceptanceTest - @ActiveProfiles({ "OpenTelemetryTest", "zos" }) + @ActiveProfiles({"OpenTelemetryTest", "zos"}) @TestPropertySource( properties = { "otel.sdk.disabled=false", @@ -118,7 +118,7 @@ void thenLogCustomAttributes() { "apiml.security.filterChainConfiguration=new" } ) - @ActiveProfiles({ "OpenTelemetryTest", "zos" }) + @ActiveProfiles({"OpenTelemetryTest", "zos"}) class WhenOnboardedService extends AcceptanceTestWithMockServices { private static final String VALID_OIDC_TOKEN = "ewogICJ0eXAiOiAiSldUIiwKICAibm9uY2UiOiAiYVZhbHVlVG9CZVZlcmlmaWVkIiwKICAiYWxnIjogIlJTMjU2IiwKICAia2lkIjogIlNlQ1JldEtleSIKfQ.ewogICJhdWQiOiAiMDAwMDAwMDMtMDAwMC0wMDAwLWMwMDAtMDAwMDAwMDAwMDAwIiwKICAiaXNzIjogImh0dHBzOi8vb2lkYy5wcm92aWRlci5vcmcvYXBwIiwKICAiaWF0IjogMTcyMjUxNDEyOSwKICAibmJmIjogMTcyMjUxNDEyOSwKICAiZXhwIjogODcyMjUxODEyNSwKICAic3ViIjogIm9pZGMudXNlcm5hbWUiCn0.c29tZVNpZ25lZEhhc2hDb2Rl"; @@ -217,7 +217,7 @@ void givenRouted_whenAuthFail_thenLog() { given() .get(basePath + "/testservice/api/v1/200") .then() - .statusCode(200); + .statusCode(200); var logRecord = assertOneLogRecordExported(); @@ -226,7 +226,7 @@ void givenRouted_whenAuthFail_thenLog() { var logBody = logRecord.getBodyValue().asString(); assertEquals("testservice", getAttribute(logBody, "service.id")); assertEquals("GET", getAttribute(logBody, "http.request.method")); - assertEquals("FAILED", getAttribute(logBody, "auth.status")); + assertEquals("ERROR", getAttribute(logBody, "auth.status")); assertEquals("localhost:testservice:" + mockServiceZoweJwt.getPort(), getAttribute(logBody, "service.instance.id")); assertEquals("200", getAttribute(logBody, "service.response_code")); assertEquals("/testservice/api/v1/200", getAttribute(logBody, "url.path")); @@ -246,27 +246,28 @@ private Object getAttribute(String logBody, String attributeName) { } @Test - @Disabled("This test is for invalid authentication (server error). To be reviewed in follow up story") void givenLoginEndpoint_thenLog() { given() .auth().preemptive() .basic("wronguser", "wrongpass") .post(basePath + "/gateway/api/v1/auth/login") .then() - .statusCode(500); + .statusCode(401); var logRecord = assertOneLogRecordExported(); assertAttributesBase(logRecord.getResource().getAttributes(), port); @SuppressWarnings("null") var logBody = logRecord.getBodyValue().asString(); - assertEquals("apicatalog", getAttribute(logBody, "service.id")); - assertEquals("GET", getAttribute(logBody, "http.request.method")); - assertEquals("FAILED", getAttribute(logBody, "auth.status")); - assertEquals("localhost:testservice:" + mockServiceZoweJwt.getPort(), getAttribute(logBody, "service.instance.id")); - assertEquals("200", getAttribute(logBody, "service.response_code")); - assertEquals("/testservice/api/v1/200", getAttribute(logBody, "url.path")); + assertEquals("gateway", getAttribute(logBody, "service.id")); + assertEquals("POST", getAttribute(logBody, "http.request.method")); + assertEquals("ERROR", getAttribute(logBody, "auth.status")); + assertEquals("EACCES: Permission is denied; the specified password is incorrect", getAttribute(logBody, "auth.error.message")); + assertEquals("Unauthorized", getAttribute(logBody, "auth.error.type")); + assertEquals("localhost:gateway:" + port, getAttribute(logBody, "service.instance.id")); + assertEquals("401", getAttribute(logBody, "service.response_code")); + assertEquals("/gateway/api/v1/auth/login", getAttribute(logBody, "url.path")); assertEquals("https", getAttribute(logBody, "url.scheme")); - assertEquals("zoweJwt", getAttribute(logBody, "auth.method")); + assertEquals("basicAuth", getAttribute(logBody, "auth.service.auth.method")); } @Test @@ -320,7 +321,7 @@ void givenNoRoute_thenLog() { given() .get(basePath + "/nonexistant/api/v1/200") .then() - .statusCode(404); + .statusCode(404); var logRecord = assertOneLogRecordExported(); assertAttributesBase(logRecord.getResource().getAttributes(), port); @@ -400,7 +401,7 @@ void givenRouted_withMisconfiguredAuthPassTicket_thenLog() { assertNull(getAttribute(logBody, "user.id")); assertEquals("testservicepterror", getAttribute(logBody, "service.id")); assertEquals("GET", getAttribute(logBody, "http.request.method")); - assertEquals("FAILED", getAttribute(logBody, "auth.status")); + assertEquals("ERROR", getAttribute(logBody, "auth.status")); assertEquals(mockServicePassTicketMisconfigured.getInstanceId(), getAttribute(logBody, "service.instance.id")); assertEquals("200", getAttribute(logBody, "service.response_code")); assertEquals("/testservicepterror/api/v1/200", getAttribute(logBody, "url.path")); @@ -465,11 +466,11 @@ private String login() { var token = given() .contentType(ContentType.JSON) .body(""" - { - "username": "USER", - "password": "validPassword" - } - """) + { + "username": "USER", + "password": "validPassword" + } + """) .log().all() .when() .post(URI.create(basePath + LOGIN_ENDPOINT)) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/filters/AbstractAuthSchemeFactory.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/filters/AbstractAuthSchemeFactory.java index 7cc474a8b8..6e561624ce 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/filters/AbstractAuthSchemeFactory.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/filters/AbstractAuthSchemeFactory.java @@ -20,6 +20,7 @@ import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.server.ServerWebExchange; @@ -96,7 +97,6 @@ * public static class Config extends AbstractAuthSchemeFactory.AbstractConfig { * } * } - * * @Data class MyResponse { * private String token; * } @@ -112,27 +112,27 @@ public abstract class AbstractAuthSchemeFactory CERTIFICATE_HEADERS_TEST = headerName -> StringUtils.equalsIgnoreCase(headerName, CERTIFICATE_HEADERS[0]) || - StringUtils.equalsIgnoreCase(headerName, CERTIFICATE_HEADERS[1]) || - StringUtils.equalsIgnoreCase(headerName, CERTIFICATE_HEADERS[2]); + StringUtils.equalsIgnoreCase(headerName, CERTIFICATE_HEADERS[1]) || + StringUtils.equalsIgnoreCase(headerName, CERTIFICATE_HEADERS[2]); private static final Predicate CREDENTIALS_COOKIE_INPUT = cookie -> StringUtils.equalsIgnoreCase(cookie.getName(), PAT_COOKIE_AUTH_NAME) || - StringUtils.equalsIgnoreCase(cookie.getName(), COOKIE_AUTH_NAME) || - StringUtils.startsWithIgnoreCase(cookie.getName(), COOKIE_AUTH_NAME + "."); + StringUtils.equalsIgnoreCase(cookie.getName(), COOKIE_AUTH_NAME) || + StringUtils.startsWithIgnoreCase(cookie.getName(), COOKIE_AUTH_NAME + "."); private static final Predicate CREDENTIALS_COOKIE = cookie -> CREDENTIALS_COOKIE_INPUT.test(cookie) || - StringUtils.equalsIgnoreCase(cookie.getName(), "jwtToken") || - StringUtils.equalsIgnoreCase(cookie.getName(), "LtpaToken2"); + StringUtils.equalsIgnoreCase(cookie.getName(), "jwtToken") || + StringUtils.equalsIgnoreCase(cookie.getName(), "LtpaToken2"); private static final Predicate CREDENTIALS_HEADER_INPUT = headerName -> StringUtils.equalsIgnoreCase(headerName, HttpHeaders.AUTHORIZATION) || - StringUtils.equalsIgnoreCase(headerName, PAT_HEADER_NAME); + StringUtils.equalsIgnoreCase(headerName, PAT_HEADER_NAME); private static final Predicate CREDENTIALS_HEADER = headerName -> CREDENTIALS_HEADER_INPUT.test(headerName) || - CERTIFICATE_HEADERS_TEST.test(headerName) || - StringUtils.equalsIgnoreCase(headerName, "X-SAF-Token") || - StringUtils.equalsIgnoreCase(headerName, CLIENT_CERT_HEADER) || - StringUtils.equalsIgnoreCase(headerName, HttpHeaders.COOKIE); + CERTIFICATE_HEADERS_TEST.test(headerName) || + StringUtils.equalsIgnoreCase(headerName, "X-SAF-Token") || + StringUtils.equalsIgnoreCase(headerName, CLIENT_CERT_HEADER) || + StringUtils.equalsIgnoreCase(headerName, HttpHeaders.COOKIE); protected final InstanceInfoService instanceInfoService; protected final MessageService messageService; @@ -209,6 +209,10 @@ protected RequestCredentials.RequestCredentialsBuilder createRequestCredentials( protected ServerHttpRequest cleanHeadersOnAuthFail(ServerWebExchange exchange, String errorMessage) { var otelContext = OtelRequestContext.of(exchange); otelContext.authenticationFailed(); + otelContext.authErrorMessage(errorMessage); + Optional.ofNullable(exchange.getResponse().getStatusCode()) + .flatMap(httpStatusCode -> Optional.ofNullable(HttpStatus.resolve(httpStatusCode.value()))) + .ifPresent(httpStatus -> otelContext.authErrorType(httpStatus.getReasonPhrase())); Optional.ofNullable(getAuthenticationScheme()).ifPresent(otelContext::authMethod); return exchange.getRequest().mutate().headers(headers -> { diff --git a/gateway-service/src/main/java/org/zowe/apiml/product/opentelemetry/OtelRequestContext.java b/gateway-service/src/main/java/org/zowe/apiml/product/opentelemetry/OtelRequestContext.java index dc4e5e433b..1d70c42771 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/product/opentelemetry/OtelRequestContext.java +++ b/gateway-service/src/main/java/org/zowe/apiml/product/opentelemetry/OtelRequestContext.java @@ -32,7 +32,8 @@ public final class OtelRequestContext { public static final String OTEL_CONTEXT = "otel-context"; private static final String OK = "OK"; - private static final String FAILED = "FAILED"; + private static final String ERROR = "ERROR"; + public static final String BASIC_AUTH_TYPE = "basicAuth"; private static final String OTEL_ATTRIBUTE_METHOD = "http.request.method"; private static final String OTEL_ATTRIBUTE_SCHEME = "url.scheme"; @@ -43,6 +44,8 @@ public final class OtelRequestContext { private static final String OTEL_ATTRIBUTE_AUTH_METHOD = "auth.service.auth.method"; private static final String OTEL_ATTRIBUTE_AUTH_SOURCE_TYPE = "auth.method"; private static final String OTEL_ATTRIBUTE_AUTH_STATUS = "auth.status"; + private static final String OTEL_ATTRIBUTE_AUTH_ERROR_TYPE = "auth.error.type"; + private static final String OTEL_ATTRIBUTE_AUTH_ERROR_MESSAGE = "auth.error.message"; private static final String OTEL_ATTRIBUTE_USER_ID = "user.id"; private static final String OTEL_ATTRIBUTE_DISTRIBUTED_USER_ID = "user.distributed.id"; @@ -97,8 +100,20 @@ public OtelRequestContext authMethod(AuthenticationScheme authenticationScheme) return put(OTEL_ATTRIBUTE_AUTH_METHOD, String.valueOf(authenticationScheme)); } + public OtelRequestContext authMethod(String authenticationScheme) { + return put(OTEL_ATTRIBUTE_AUTH_METHOD, authenticationScheme); + } + public OtelRequestContext authenticationFailed() { - return put(OTEL_ATTRIBUTE_AUTH_STATUS, FAILED); + return put(OTEL_ATTRIBUTE_AUTH_STATUS, ERROR); + } + + public OtelRequestContext authErrorType(String authErrorType) { + return put(OTEL_ATTRIBUTE_AUTH_ERROR_TYPE, authErrorType); + } + + public OtelRequestContext authErrorMessage(String authErrorMessage) { + return put(OTEL_ATTRIBUTE_AUTH_ERROR_MESSAGE, authErrorMessage); } public OtelRequestContext authenticationSuccess() { diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/filters/AbstractTokenFilterFactoryTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/filters/AbstractTokenFilterFactoryTest.java index 0631263bd9..fb152e9cda 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/filters/AbstractTokenFilterFactoryTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/filters/AbstractTokenFilterFactoryTest.java @@ -18,6 +18,7 @@ import org.mockito.ArgumentCaptor; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; @@ -73,7 +74,7 @@ class ValidResponse { @Test void givenHeaderResponse_whenHandling_thenUpdateTheRequest() { - var request = testRequestMutation(new AbstractAuthSchemeFactory.AuthorizationResponse<>(null,ZaasTokenResponse.builder() + var request = testRequestMutation(new AbstractAuthSchemeFactory.AuthorizationResponse<>(null, ZaasTokenResponse.builder() .headerName("headerName") .token("headerValue") .build() @@ -83,13 +84,13 @@ void givenHeaderResponse_whenHandling_thenUpdateTheRequest() { @Test void givenCookieResponse_whenHandling_thenUpdateTheRequest() { - var request = testRequestMutation(new AbstractAuthSchemeFactory.AuthorizationResponse<>(null,ZaasTokenResponse.builder() + var request = testRequestMutation(new AbstractAuthSchemeFactory.AuthorizationResponse<>(null, ZaasTokenResponse.builder() .cookieName("cookieName") .token("cookieValue") .build() )); assertEquals("cookieName=cookieValue", request.getHeaders().getFirst("cookie")); - assertEquals("Bearer cookieValue" , request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION)); + assertEquals("Bearer cookieValue", request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION)); } } @@ -126,7 +127,7 @@ void givenEmptyResponseWithError_whenHandling_thenProvideErrorHeader() { @Test void givenCookieAndHeaderInResponse_whenHandling_thenSetBoth() { - var request = testRequestMutation(new AbstractAuthSchemeFactory.AuthorizationResponse<>(null,ZaasTokenResponse.builder() + var request = testRequestMutation(new AbstractAuthSchemeFactory.AuthorizationResponse<>(null, ZaasTokenResponse.builder() .cookieName("cookie") .headerName("header") .token("jwt") @@ -144,20 +145,24 @@ void givenCookieAndHeaderInResponse_whenHandling_thenSetBoth() { class Otel { MockServerHttpRequest request = MockServerHttpRequest.get("/aPath").build(); - MockServerWebExchange exchange = MockServerWebExchange.from(request); + MockServerWebExchange exchange; OtelRequestContext otelRequestContext; @BeforeEach void mockOtelContext() { + exchange = MockServerWebExchange.from(request); otelRequestContext = spy(OtelRequestContext.of(exchange)); exchange.getAttributes().put("otel-context", otelRequestContext); } @Test void givenOtelRequestContext_whenFail_thenCallAuthenticationFailed() { + exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); spy(AbstractAuthSchemeFactory.class).cleanHeadersOnAuthFail(exchange, "test"); verify(otelRequestContext, times(1)).authenticationFailed(); + verify(otelRequestContext, times(1)).authErrorMessage("test"); + verify(otelRequestContext, times(1)).authErrorType(HttpStatus.FORBIDDEN.getReasonPhrase()); } @Test diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/filters/RoutingConfigurationErrorFilterFactoryTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/filters/RoutingConfigurationErrorFilterFactoryTest.java index db29456a3a..0f0a1f7cfc 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/filters/RoutingConfigurationErrorFilterFactoryTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/filters/RoutingConfigurationErrorFilterFactoryTest.java @@ -10,10 +10,11 @@ package org.zowe.apiml.gateway.filters; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.http.HttpStatus; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.zowe.apiml.auth.AuthenticationScheme; @@ -33,10 +34,11 @@ class RoutingConfigurationErrorFilterFactoryTest { private GatewayFilter filter; private MockServerHttpRequest request = MockServerHttpRequest.get("https://localhost/some/url").build(); - private MockServerWebExchange exchange = MockServerWebExchange.from(request); + private MockServerWebExchange exchange; - @BeforeAll + @BeforeEach void init() { + exchange = MockServerWebExchange.from(request); var config = new RoutingConfigurationErrorFilterFactory.Config(); config.setMessage(MESSAGE); config.setAuthenticationScheme("safIdt"); @@ -47,13 +49,31 @@ void init() { } @Test - void givenConfig_whenApply_thenSetAuthInformation() { + void givenConfig_whenApply_thenSetAuthInformationWithoutErrorType() { var otelContext = spy(OtelRequestContext.of(exchange)); exchange.getAttributes().put(OtelRequestContext.OTEL_CONTEXT, otelContext); StepVerifier.create(filter.filter(exchange, e -> Mono.empty())).verifyComplete(); verify(otelContext).authenticationFailed(); + verify(otelContext).authErrorMessage(MESSAGE); + + verify(otelContext).authMethod(AuthenticationScheme.SAF_IDT); + verify(underTest).cleanHeadersOnAuthFail(exchange, MESSAGE); + } + + @Test + void givenConfig_whenApply_thenSetFailedAuthInformationWithErrorType() { + var otelContext = spy(OtelRequestContext.of(exchange)); + exchange.getAttributes().put(OtelRequestContext.OTEL_CONTEXT, otelContext); + exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); + + StepVerifier.create(filter.filter(exchange, e -> Mono.empty())).verifyComplete(); + + verify(otelContext).authenticationFailed(); + verify(otelContext).authErrorMessage(MESSAGE); + verify(otelContext).authErrorType(HttpStatus.UNAUTHORIZED.getReasonPhrase()); + verify(otelContext).authMethod(AuthenticationScheme.SAF_IDT); verify(underTest).cleanHeadersOnAuthFail(exchange, MESSAGE); } diff --git a/gateway-service/src/test/java/org/zowe/apiml/product/opentelemetry/OtelRequestContextTest.java b/gateway-service/src/test/java/org/zowe/apiml/product/opentelemetry/OtelRequestContextTest.java index 922b156005..e16f595652 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/product/opentelemetry/OtelRequestContextTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/product/opentelemetry/OtelRequestContextTest.java @@ -113,7 +113,19 @@ void givenOtelContext_whenSetZoweJwtAuthMethod_thenTransformToString() { @Test void givenOtelContext_whenAuthenticationFailed_thenStoreFailedStringAsStatus() { OtelRequestContext.of(exchange).authenticationFailed(); - assertEquals("FAILED", getValue("auth.status")); + assertEquals("ERROR", getValue("auth.status")); + } + + @Test + void givenOtelContext_whenAuthErrorMessage_thenStoreMessageAsAuthErrorMessage() { + OtelRequestContext.of(exchange).authErrorMessage("Invalid credentials"); + assertEquals("Invalid credentials", getValue("auth.error.message")); + } + + @Test + void givenOtelContext_whenAuthErrorType_thenStoreErrorTypeAsAuthErrorType() { + OtelRequestContext.of(exchange).authErrorType("Forbidden"); + assertEquals("Forbidden", getValue("auth.error.type")); } @Test @@ -154,7 +166,8 @@ void givenInvalidData_whenObjectMapperFails_thenThrowIllegalStateException() thr exchange = MockServerWebExchange.from(request); var objectMapper = mock(ObjectMapper.class); var otelRequestContext = spy(OtelRequestContext.of(exchange)); - var jsonProcessingException = new JsonProcessingException("test") {}; + var jsonProcessingException = new JsonProcessingException("test") { + }; doReturn(objectMapper).when(otelRequestContext).getObjectMapper(); doThrow(jsonProcessingException).when(objectMapper).writeValueAsString(any());