From b8a354941afe4e7769902081c2ea1f39106ea8db Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Tue, 23 Dec 2025 11:34:34 -0500 Subject: [PATCH 1/4] Skipping auth call if ccm is not configured --- .../xpack/inference/InferencePlugin.java | 4 +- .../TransportGetInferenceServicesAction.java | 2 +- .../TransportPutCCMConfigurationAction.java | 4 +- ...nceServiceAuthorizationRequestHandler.java | 139 ++++++--- ...rviceAuthorizationRequestHandlerTests.java | 264 +++++++++++++++++- 5 files changed, 360 insertions(+), 53 deletions(-) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java index f28890af496e4..0e96b0af3fa7d 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java @@ -487,7 +487,9 @@ private CCMRelatedComponents createCCMDependentComponents( var authorizationHandler = new ElasticInferenceServiceAuthorizationRequestHandler( inferenceServiceSettings.getElasticInferenceServiceUrl(), services.threadPool(), - ccmAuthApplierFactory + ccmAuthApplierFactory, + ccmFeature, + ccmService ); var authTaskExecutor = AuthorizationTaskExecutor.create( diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceServicesAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceServicesAction.java index e776ba0690613..8a7d5f3191c20 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceServicesAction.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceServicesAction.java @@ -158,7 +158,7 @@ private void getEisAuthorization(ActionListener getServiceConfigurationsForServices( diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportPutCCMConfigurationAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportPutCCMConfigurationAction.java index f7e3c1e8f3896..db9d253361b28 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportPutCCMConfigurationAction.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportPutCCMConfigurationAction.java @@ -112,7 +112,9 @@ protected void masterOperation( var authRequestHandler = new ElasticInferenceServiceAuthorizationRequestHandler( eisSettings.getElasticInferenceServiceUrl(), threadPool, - new ValidationAuthenticationFactory(request.getApiKey()) + new ValidationAuthenticationFactory(request.getApiKey()), + ccmFeature, + ccmService ); var errorListener = authValidationListener.delegateResponse((delegate, exception) -> { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java index 9ed3e683b0829..f970f7bb494e5 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java @@ -23,6 +23,8 @@ import org.elasticsearch.xpack.inference.external.http.sender.Sender; import org.elasticsearch.xpack.inference.services.elastic.ElasticInferenceServiceResponseHandler; import org.elasticsearch.xpack.inference.services.elastic.ccm.AuthenticationFactory; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMFeature; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMService; import org.elasticsearch.xpack.inference.services.elastic.request.ElasticInferenceServiceAuthorizationRequest; import org.elasticsearch.xpack.inference.services.elastic.response.ElasticInferenceServiceAuthorizationResponseEntity; import org.elasticsearch.xpack.inference.telemetry.TraceContext; @@ -56,17 +58,23 @@ private static ResponseHandler createAuthResponseHandler() { private final Logger logger; private final CountDownLatch requestCompleteLatch = new CountDownLatch(1); private final AuthenticationFactory authFactory; + private final CCMFeature ccmFeature; + private final CCMService ccmService; public ElasticInferenceServiceAuthorizationRequestHandler( @Nullable String baseUrl, ThreadPool threadPool, - AuthenticationFactory authFactory + AuthenticationFactory authFactory, + CCMFeature ccmFeature, + CCMService ccmService ) { this( baseUrl, Objects.requireNonNull(threadPool), LogManager.getLogger(ElasticInferenceServiceAuthorizationRequestHandler.class), - authFactory + authFactory, + ccmFeature, + ccmService ); } @@ -75,12 +83,16 @@ public ElasticInferenceServiceAuthorizationRequestHandler( @Nullable String baseUrl, ThreadPool threadPool, Logger logger, - AuthenticationFactory authFactory + AuthenticationFactory authFactory, + CCMFeature ccmFeature, + CCMService ccmService ) { this.baseUrl = baseUrl; this.threadPool = Objects.requireNonNull(threadPool); this.logger = Objects.requireNonNull(logger); this.authFactory = Objects.requireNonNull(authFactory); + this.ccmFeature = Objects.requireNonNull(ccmFeature); + this.ccmService = Objects.requireNonNull(ccmService); } /** @@ -89,57 +101,98 @@ public ElasticInferenceServiceAuthorizationRequestHandler( * @param sender a {@link Sender} for making the request to the Elastic Inference Service */ public void getAuthorization(ActionListener listener, Sender sender) { - try { - logger.debug("Retrieving authorization information from the Elastic Inference Service."); + getAuthorizationHelper(listener, sender, false); + } + + /** + * Skips retrieving the authorization information from Elastic Inference Service if CCM is not configured, + * and it is a supported environment, a supported environment would be on-prem or ECK. ECH and serverless are not supported + * environments for CCM (because they can already connect to EIS). For environments where CCM is not supported, it will always + * attempt to retrieve the authorization information. + * @param listener a listener to receive the response + * @param sender a {@link Sender} for making the request to the Elastic Inference Service + */ + public void getAuthorizationSkippingIfCcmNotConfigured( + ActionListener listener, + Sender sender + ) { + getAuthorizationHelper(listener, sender, true); + } - if (Strings.isNullOrEmpty(baseUrl)) { - logger.debug("The base URL for the authorization service is not valid, rejecting authorization."); - listener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); + private void getAuthorizationHelper( + ActionListener listener, + Sender sender, + boolean skipIfCcmNotConfigured + ) { + var countdownListener = ActionListener.runAfter(listener, requestCompleteLatch::countDown); + + try { + if (skipIfCcmNotConfigured == false || ccmFeature.isCcmSupportedEnvironment() == false) { + retrieveAuthorizationInformation(countdownListener, sender); return; } - var handleFailuresListener = listener.delegateResponse((authModelListener, e) -> { - // unwrap because it's likely a retry exception - var exception = ExceptionsHelper.unwrapCause(e); - - logger.warn(Strings.format(FAILED_TO_RETRIEVE_MESSAGE + " Encountered an exception: %s", exception), exception); - authModelListener.onFailure(e); + var isCcmEnabledListener = ActionListener.wrap(response -> { + if (response == null || response == false) { + logger.debug("CCM is not configured, skipping authorization request to Elastic Inference Service."); + countdownListener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); + } else { + retrieveAuthorizationInformation(countdownListener, sender); + } + }, e -> { + logger.atDebug().withThrowable(e).log("Failed to determine if CCM is configured, returning unauthorized."); + countdownListener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); }); - SubscribableListener.newForked(sender::startAsynchronously) - .andThen(authFactory::getAuthenticationApplier) - .andThen((authListener, authApplier) -> { - var requestMetadata = extractRequestMetadataFromThreadContext(threadPool.getThreadContext()); - var request = new ElasticInferenceServiceAuthorizationRequest( - baseUrl, - getCurrentTraceInfo(), - requestMetadata, - authApplier - ); - sender.sendWithoutQueuing(logger, request, AUTH_RESPONSE_HANDLER, DEFAULT_AUTH_TIMEOUT, authListener); - }) - .andThenApply(authResult -> { - if (authResult instanceof ElasticInferenceServiceAuthorizationResponseEntity authResponseEntity) { - logger.debug(() -> Strings.format("Received authorization information from gateway %s", authResponseEntity)); - return ElasticInferenceServiceAuthorizationModel.of(authResponseEntity, baseUrl); - } - - var errorMessage = Strings.format( - "%s Received an invalid response type from the Elastic Inference Service: %s", - FAILED_TO_RETRIEVE_MESSAGE, - authResult.getClass().getSimpleName() - ); - - logger.warn(errorMessage); - throw new ElasticsearchException(errorMessage); - }) - .addListener(ActionListener.runAfter(handleFailuresListener, requestCompleteLatch::countDown)); + ccmService.isEnabled(isCcmEnabledListener); } catch (Exception e) { logger.warn(Strings.format("Retrieving the authorization information encountered an exception: %s", e)); - requestCompleteLatch.countDown(); + countdownListener.onFailure(e); } } + private void retrieveAuthorizationInformation(ActionListener listener, Sender sender) { + logger.debug("Retrieving authorization information from the Elastic Inference Service."); + + if (Strings.isNullOrEmpty(baseUrl)) { + logger.debug("The base URL for the authorization service is not valid, rejecting authorization."); + listener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); + return; + } + + var handleFailuresListener = listener.delegateResponse((authModelListener, e) -> { + // unwrap because it's likely a retry exception + var exception = ExceptionsHelper.unwrapCause(e); + + logger.warn(Strings.format(FAILED_TO_RETRIEVE_MESSAGE + " Encountered an exception: %s", exception), exception); + authModelListener.onFailure(e); + }); + + SubscribableListener.newForked(sender::startAsynchronously) + .andThen(authFactory::getAuthenticationApplier) + .andThen((authListener, authApplier) -> { + var requestMetadata = extractRequestMetadataFromThreadContext(threadPool.getThreadContext()); + var request = new ElasticInferenceServiceAuthorizationRequest(baseUrl, getCurrentTraceInfo(), requestMetadata, authApplier); + sender.sendWithoutQueuing(logger, request, AUTH_RESPONSE_HANDLER, DEFAULT_AUTH_TIMEOUT, authListener); + }) + .andThenApply(authResult -> { + if (authResult instanceof ElasticInferenceServiceAuthorizationResponseEntity authResponseEntity) { + logger.debug(() -> Strings.format("Received authorization information from gateway %s", authResponseEntity)); + return ElasticInferenceServiceAuthorizationModel.of(authResponseEntity, baseUrl); + } + + var errorMessage = Strings.format( + "%s Received an invalid response type from the Elastic Inference Service: %s", + FAILED_TO_RETRIEVE_MESSAGE, + authResult.getClass().getSimpleName() + ); + + logger.warn(errorMessage); + throw new ElasticsearchException(errorMessage); + }) + .addListener(handleFailuresListener); + } + private TraceContext getCurrentTraceInfo() { var traceParent = threadPool.getThreadContext().getHeader(Task.TRACE_PARENT_HTTP_HEADER); var traceState = threadPool.getThreadContext().getHeader(Task.TRACE_STATE); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java index f899d664561e5..025c0ea91b2b5 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java @@ -28,6 +28,8 @@ import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; import org.elasticsearch.xpack.inference.logging.ThrottlerManager; import org.elasticsearch.xpack.inference.services.elastic.ElasticInferenceServiceModel; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMFeature; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMService; import org.junit.After; import org.junit.Before; import org.mockito.ArgumentCaptor; @@ -51,11 +53,13 @@ import static org.elasticsearch.xpack.inference.services.elastic.response.ElasticInferenceServiceAuthorizationResponseEntityTests.getEisElserAuthorizationResponse; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -85,7 +89,14 @@ public void shutdown() throws IOException { public void testDoesNotAttempt_ToRetrieveAuthorization_IfBaseUrlIsNull() throws Exception { var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); var logger = mock(Logger.class); - var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler(null, threadPool, logger, createNoopApplierFactory()); + var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( + null, + threadPool, + logger, + createNoopApplierFactory(), + createMockCcmFeature(false), + createMockCcmService(false) + ); try (var sender = senderFactory.createSender()) { PlainActionFuture listener = new PlainActionFuture<>(); @@ -107,7 +118,14 @@ public void testDoesNotAttempt_ToRetrieveAuthorization_IfBaseUrlIsNull() throws public void testDoesNotAttempt_ToRetrieveAuthorization_IfBaseUrlIsEmpty() throws Exception { var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); var logger = mock(Logger.class); - var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler("", threadPool, logger, createNoopApplierFactory()); + var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( + "", + threadPool, + logger, + createNoopApplierFactory(), + createMockCcmFeature(false), + createMockCcmService(false) + ); try (var sender = senderFactory.createSender()) { PlainActionFuture listener = new PlainActionFuture<>(); @@ -134,7 +152,9 @@ public void testGetAuthorization_FailsWhenAnInvalidFieldIsFound() throws IOExcep eisGatewayUrl, threadPool, logger, - createNoopApplierFactory() + createNoopApplierFactory(), + createMockCcmFeature(false), + createMockCcmService(false) ); try (var sender = senderFactory.createSender()) { @@ -185,11 +205,16 @@ public void testGetAuthorization_ReturnsAValidResponse() throws IOException { var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); var eisGatewayUrl = getUrl(webServer); var logger = mock(Logger.class); + var mockCcmFeature = createMockCcmFeature(false); + var mockCcmService = createMockCcmService(false); + var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( eisGatewayUrl, threadPool, logger, - createNoopApplierFactory() + createNoopApplierFactory(), + mockCcmFeature, + mockCcmService ); try (var sender = senderFactory.createSender()) { @@ -227,6 +252,13 @@ public void testGetAuthorization_ReturnsAValidResponse() throws IOException { assertThat(message, is("Retrieving authorization information from the Elastic Inference Service.")); assertNoAuthHeader(webServer.requests()); + + authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); + + // It should never check if the CCM environment is supported since getAuthorization does not attempt to skip the authorization + // check + verify(mockCcmFeature, never()).isCcmSupportedEnvironment(); + verify(mockCcmService, never()).isEnabled(any()); } } @@ -235,6 +267,197 @@ private static void assertNoAuthHeader(List requests) { assertNull(requests.get(0).getHeader(HttpHeaders.AUTHORIZATION)); } + public void testGetAuthorizationSkippingIfCcmNotConfigured_ReturnsFailure_WhenExceptionThrown() throws IOException { + var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); + var eisGatewayUrl = getUrl(webServer); + var logger = mock(Logger.class); + + var exceptionToThrow = new IllegalStateException("exception"); + var mockCcmFeature = mock(CCMFeature.class); + when(mockCcmFeature.isCcmSupportedEnvironment()).thenThrow(exceptionToThrow); + var mockCcmService = createMockCcmService(false); + + var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( + eisGatewayUrl, + threadPool, + logger, + createNoopApplierFactory(), + mockCcmFeature, + mockCcmService + ); + + try (var sender = senderFactory.createSender()) { + var responseData = getEisAuthorizationResponseWithMultipleEndpoints(eisGatewayUrl); + + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson())); + + PlainActionFuture listener = new PlainActionFuture<>(); + authHandler.getAuthorizationSkippingIfCcmNotConfigured(listener, sender); + + var exception = expectThrows(IllegalStateException.class, () -> listener.actionGet(TIMEOUT)); + assertThat(exception, is(exceptionToThrow)); + + // There should be no requests made to EIS because it is not configured + assertThat(webServer.requests().size(), is(0)); + + authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); + + verify(mockCcmFeature, times(1)).isCcmSupportedEnvironment(); + verify(mockCcmService, never()).isEnabled(any()); + } + } + + public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsAValidResponse_WhenNotCcmSupportedEnvironment() throws IOException { + var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); + var eisGatewayUrl = getUrl(webServer); + var logger = mock(Logger.class); + + var mockCcmFeature = createMockCcmFeature(false); + var mockCcmService = createMockCcmService(false); + + var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( + eisGatewayUrl, + threadPool, + logger, + createNoopApplierFactory(), + mockCcmFeature, + mockCcmService + ); + + try (var sender = senderFactory.createSender()) { + var responseData = getEisAuthorizationResponseWithMultipleEndpoints(eisGatewayUrl); + + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson())); + + PlainActionFuture listener = new PlainActionFuture<>(); + authHandler.getAuthorizationSkippingIfCcmNotConfigured(listener, sender); + + var authResponse = listener.actionGet(TIMEOUT); + assertThat( + authResponse.getTaskTypes(), + is( + EnumSet.of( + TaskType.CHAT_COMPLETION, + TaskType.SPARSE_EMBEDDING, + TaskType.TEXT_EMBEDDING, + TaskType.RERANK, + TaskType.COMPLETION + ) + ) + ); + assertThat(authResponse.getEndpointIds(), containsInAnyOrder(responseData.inferenceIds().toArray(String[]::new))); + assertTrue(authResponse.isAuthorized()); + assertThat( + authResponse.getEndpoints(responseData.inferenceIds()), + containsInAnyOrder(responseData.expectedEndpoints().toArray(ElasticInferenceServiceModel[]::new)) + ); + + assertNoAuthHeader(webServer.requests()); + + authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); + + verify(mockCcmFeature, times(1)).isCcmSupportedEnvironment(); + verify(mockCcmService, never()).isEnabled(any()); + } + } + + public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsAValidResponse_WhenCcmSupportedEnvironmentAndConfigured() + throws IOException { + var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); + var eisGatewayUrl = getUrl(webServer); + var logger = mock(Logger.class); + + var mockCcmFeature = createMockCcmFeature(true); + var mockCcmService = createMockCcmService(true); + + var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( + eisGatewayUrl, + threadPool, + logger, + createNoopApplierFactory(), + mockCcmFeature, + mockCcmService + ); + + try (var sender = senderFactory.createSender()) { + var responseData = getEisAuthorizationResponseWithMultipleEndpoints(eisGatewayUrl); + + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson())); + + PlainActionFuture listener = new PlainActionFuture<>(); + authHandler.getAuthorizationSkippingIfCcmNotConfigured(listener, sender); + + var authResponse = listener.actionGet(TIMEOUT); + assertThat( + authResponse.getTaskTypes(), + is( + EnumSet.of( + TaskType.CHAT_COMPLETION, + TaskType.SPARSE_EMBEDDING, + TaskType.TEXT_EMBEDDING, + TaskType.RERANK, + TaskType.COMPLETION + ) + ) + ); + assertThat(authResponse.getEndpointIds(), containsInAnyOrder(responseData.inferenceIds().toArray(String[]::new))); + assertTrue(authResponse.isAuthorized()); + assertThat( + authResponse.getEndpoints(responseData.inferenceIds()), + containsInAnyOrder(responseData.expectedEndpoints().toArray(ElasticInferenceServiceModel[]::new)) + ); + + assertNoAuthHeader(webServer.requests()); + + authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); + + verify(mockCcmFeature, times(1)).isCcmSupportedEnvironment(); + verify(mockCcmService, times(1)).isEnabled(any()); + } + } + + public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsUnauthorized_WhenCcmSupportedEnvironmentAndNotConfigured() + throws IOException { + var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); + var eisGatewayUrl = getUrl(webServer); + var logger = mock(Logger.class); + + var mockCcmFeature = createMockCcmFeature(true); + var mockCcmService = createMockCcmService(false); + + var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( + eisGatewayUrl, + threadPool, + logger, + createNoopApplierFactory(), + mockCcmFeature, + mockCcmService + ); + + try (var sender = senderFactory.createSender()) { + var responseData = getEisAuthorizationResponseWithMultipleEndpoints(eisGatewayUrl); + + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson())); + + PlainActionFuture listener = new PlainActionFuture<>(); + authHandler.getAuthorizationSkippingIfCcmNotConfigured(listener, sender); + + var authResponse = listener.actionGet(TIMEOUT); + assertThat(authResponse.getTaskTypes(), is(EnumSet.noneOf(TaskType.class))); + assertThat(authResponse.getEndpointIds(), empty()); + assertFalse(authResponse.isAuthorized()); + assertThat(authResponse.getEndpoints(responseData.inferenceIds()), empty()); + + // There should be no requests made to EIS because it is not configured + assertThat(webServer.requests().size(), is(0)); + + authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); + + verify(mockCcmFeature, times(1)).isCcmSupportedEnvironment(); + verify(mockCcmService, times(1)).isEnabled(any()); + } + } + public void testGetAuthorization_ReturnsAValidResponse_WithAuthHeader() throws IOException { var secret = "secret-token"; var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); @@ -245,7 +468,9 @@ public void testGetAuthorization_ReturnsAValidResponse_WithAuthHeader() throws I eisGatewayUrl, threadPool, logger, - createApplierFactory(secret) + createApplierFactory(secret), + createMockCcmFeature(false), + createMockCcmService(false) ); var elserResponseBody = getEisElserAuthorizationResponse(eisGatewayUrl).responseJson(); @@ -285,7 +510,9 @@ public void testGetAuthorization_OnResponseCalledOnce() throws IOException { eisGatewayUrl, threadPool, logger, - createNoopApplierFactory() + createNoopApplierFactory(), + createMockCcmFeature(false), + createMockCcmService(false) ); PlainActionFuture listener = new PlainActionFuture<>(); @@ -325,7 +552,14 @@ public void testGetAuthorization_InvalidResponse() throws IOException { }).when(senderMock).sendWithoutQueuing(any(), any(), any(), any(), any()); var logger = mock(Logger.class); - var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler("abc", threadPool, logger, createNoopApplierFactory()); + var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( + "abc", + threadPool, + logger, + createNoopApplierFactory(), + createMockCcmFeature(false), + createMockCcmService(false) + ); try (var sender = senderFactory.createSender()) { PlainActionFuture listener = new PlainActionFuture<>(); @@ -341,4 +575,20 @@ public void testGetAuthorization_InvalidResponse() throws IOException { assertThat(message, containsString("Failed to retrieve the authorization information from the Elastic Inference Service.")); } } + + private static CCMFeature createMockCcmFeature(boolean isCcmSupportedEnvironment) { + var ccmFeature = mock(CCMFeature.class); + when(ccmFeature.isCcmSupportedEnvironment()).thenReturn(isCcmSupportedEnvironment); + return ccmFeature; + } + + private static CCMService createMockCcmService(boolean isEnabled) { + var ccmService = mock(CCMService.class); + doAnswer(invocation -> { + ActionListener listener = invocation.getArgument(0); + listener.onResponse(isEnabled); + return Void.TYPE; + }).when(ccmService).isEnabled(any()); + return ccmService; + } } From 34d632044d17e239d19adcc6eca570031f538d51 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Wed, 7 Jan 2026 17:06:50 -0500 Subject: [PATCH 2/4] Addressing feedback --- .../TransportGetInferenceServicesAction.java | 2 +- ...nceServiceAuthorizationRequestHandler.java | 48 +++---- ...rviceAuthorizationRequestHandlerTests.java | 127 +++++++++--------- 3 files changed, 88 insertions(+), 89 deletions(-) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceServicesAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceServicesAction.java index 8a7d5f3191c20..fd4b981375009 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceServicesAction.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceServicesAction.java @@ -158,7 +158,7 @@ private void getEisAuthorization(ActionListener getServiceConfigurationsForServices( diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java index f970f7bb494e5..baf05e0847f46 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java @@ -101,50 +101,46 @@ public ElasticInferenceServiceAuthorizationRequestHandler( * @param sender a {@link Sender} for making the request to the Elastic Inference Service */ public void getAuthorization(ActionListener listener, Sender sender) { - getAuthorizationHelper(listener, sender, false); + getAuthorization(listener, sender, false); } /** - * Skips retrieving the authorization information from Elastic Inference Service if CCM is not configured, - * and it is a supported environment, a supported environment would be on-prem or ECK. ECH and serverless are not supported + * Retrieves the authorization information from Elastic Inference Service. This will skip making a request if CCM is not enabled + * and it is a supported environment. A supported environment is on-prem or ECK. ECH and serverless are not supported * environments for CCM (because they can already connect to EIS). For environments where CCM is not supported, it will always * attempt to retrieve the authorization information. * @param listener a listener to receive the response * @param sender a {@link Sender} for making the request to the Elastic Inference Service */ - public void getAuthorizationSkippingIfCcmNotConfigured( - ActionListener listener, - Sender sender - ) { - getAuthorizationHelper(listener, sender, true); + public void getAuthorizationIfPermittedEnvironment(ActionListener listener, Sender sender) { + getAuthorization(listener, sender, true); } - private void getAuthorizationHelper( + private void getAuthorization( ActionListener listener, Sender sender, - boolean skipIfCcmNotConfigured + boolean checkCcmState ) { var countdownListener = ActionListener.runAfter(listener, requestCompleteLatch::countDown); try { - if (skipIfCcmNotConfigured == false || ccmFeature.isCcmSupportedEnvironment() == false) { - retrieveAuthorizationInformation(countdownListener, sender); - return; - } - - var isCcmEnabledListener = ActionListener.wrap(response -> { - if (response == null || response == false) { - logger.debug("CCM is not configured, skipping authorization request to Elastic Inference Service."); + if (checkCcmState && ccmFeature.isCcmSupportedEnvironment()) { + var isCcmEnabledListener = ActionListener.wrap(enabled -> { + if (enabled == null || enabled == false) { + logger.debug("CCM is not enabled, skipping authorization request to Elastic Inference Service."); + countdownListener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); + } else { + retrieveAuthorizationInformation(countdownListener, sender); + } + }, e -> { + logger.atDebug().withThrowable(e).log("Failed to determine if CCM is configured, returning unauthorized."); countdownListener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); - } else { - retrieveAuthorizationInformation(countdownListener, sender); - } - }, e -> { - logger.atDebug().withThrowable(e).log("Failed to determine if CCM is configured, returning unauthorized."); - countdownListener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); - }); + }); - ccmService.isEnabled(isCcmEnabledListener); + ccmService.isEnabled(isCcmEnabledListener); + } else { + retrieveAuthorizationInformation(countdownListener, sender); + } } catch (Exception e) { logger.warn(Strings.format("Retrieving the authorization information encountered an exception: %s", e)); countdownListener.onFailure(e); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java index 025c0ea91b2b5..469c47359b215 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java @@ -38,7 +38,6 @@ import java.util.EnumSet; import java.util.List; import java.util.Set; -import java.util.concurrent.TimeUnit; import static org.elasticsearch.xpack.inference.Utils.inferenceUtilityExecutors; import static org.elasticsearch.xpack.inference.Utils.mockClusterServiceEmpty; @@ -65,8 +64,6 @@ import static org.mockito.Mockito.when; public class ElasticInferenceServiceAuthorizationRequestHandlerTests extends ESTestCase { - private static final TimeValue TIMEOUT = new TimeValue(30, TimeUnit.SECONDS); - private final MockWebServer webServer = new MockWebServer(); private ThreadPool threadPool; @@ -102,7 +99,7 @@ public void testDoesNotAttempt_ToRetrieveAuthorization_IfBaseUrlIsNull() throws PlainActionFuture listener = new PlainActionFuture<>(); authHandler.getAuthorization(listener, sender); - var authResponse = listener.actionGet(TIMEOUT); + var authResponse = listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT); assertTrue(authResponse.getTaskTypes().isEmpty()); assertTrue(authResponse.getEndpointIds().isEmpty()); assertFalse(authResponse.isAuthorized()); @@ -131,7 +128,7 @@ public void testDoesNotAttempt_ToRetrieveAuthorization_IfBaseUrlIsEmpty() throws PlainActionFuture listener = new PlainActionFuture<>(); authHandler.getAuthorization(listener, sender); - var authResponse = listener.actionGet(TIMEOUT); + var authResponse = listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT); assertTrue(authResponse.getTaskTypes().isEmpty()); assertTrue(authResponse.getEndpointIds().isEmpty()); assertFalse(authResponse.isAuthorized()); @@ -178,7 +175,7 @@ public void testGetAuthorization_FailsWhenAnInvalidFieldIsFound() throws IOExcep PlainActionFuture listener = new PlainActionFuture<>(); authHandler.getAuthorization(listener, sender); - var exception = expectThrows(XContentParseException.class, () -> listener.actionGet(TIMEOUT)); + var exception = expectThrows(XContentParseException.class, () -> listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT)); assertThat(exception.getMessage(), containsString("failed to parse field [inference_endpoints]")); var stringCaptor = ArgumentCaptor.forClass(String.class); @@ -225,7 +222,7 @@ public void testGetAuthorization_ReturnsAValidResponse() throws IOException { PlainActionFuture listener = new PlainActionFuture<>(); authHandler.getAuthorization(listener, sender); - var authResponse = listener.actionGet(TIMEOUT); + var authResponse = listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT); assertThat( authResponse.getTaskTypes(), is( @@ -253,7 +250,7 @@ public void testGetAuthorization_ReturnsAValidResponse() throws IOException { assertNoAuthHeader(webServer.requests()); - authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); + authHandler.waitForAuthRequestCompletion(ESTestCase.TEST_REQUEST_TIMEOUT); // It should never check if the CCM environment is supported since getAuthorization does not attempt to skip the authorization // check @@ -267,7 +264,7 @@ private static void assertNoAuthHeader(List requests) { assertNull(requests.get(0).getHeader(HttpHeaders.AUTHORIZATION)); } - public void testGetAuthorizationSkippingIfCcmNotConfigured_ReturnsFailure_WhenExceptionThrown() throws IOException { + public void testGetAuthorizationIfPermittedEnvironment_ReturnsFailure_WhenExceptionThrown() throws IOException { var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); var eisGatewayUrl = getUrl(webServer); var logger = mock(Logger.class); @@ -287,34 +284,38 @@ public void testGetAuthorizationSkippingIfCcmNotConfigured_ReturnsFailure_WhenEx ); try (var sender = senderFactory.createSender()) { - var responseData = getEisAuthorizationResponseWithMultipleEndpoints(eisGatewayUrl); - - webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson())); - PlainActionFuture listener = new PlainActionFuture<>(); - authHandler.getAuthorizationSkippingIfCcmNotConfigured(listener, sender); + authHandler.getAuthorizationIfPermittedEnvironment(listener, sender); - var exception = expectThrows(IllegalStateException.class, () -> listener.actionGet(TIMEOUT)); + var exception = expectThrows(IllegalStateException.class, () -> listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT)); assertThat(exception, is(exceptionToThrow)); - // There should be no requests made to EIS because it is not configured - assertThat(webServer.requests().size(), is(0)); + // There should be no requests made to EIS because an exception should be thrown before the request is made + assertThat(webServer.requests(), empty()); authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); - verify(mockCcmFeature, times(1)).isCcmSupportedEnvironment(); verify(mockCcmService, never()).isEnabled(any()); } } - public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsAValidResponse_WhenNotCcmSupportedEnvironment() throws IOException { + public void testGetAuthorizationIfPermittedEnvironment_ReturnsAValidResponse_WhenNotCcmSupportedEnvironment() throws IOException { var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); var eisGatewayUrl = getUrl(webServer); - var logger = mock(Logger.class); var mockCcmFeature = createMockCcmFeature(false); - var mockCcmService = createMockCcmService(false); + var mockCcmService = createMockCcmService(randomBoolean()); + + assertReturnsValidResponse(eisGatewayUrl, mockCcmFeature, mockCcmService, senderFactory, 0); + } + private void assertReturnsValidResponse( + String eisGatewayUrl, + CCMFeature mockCcmFeature, + CCMService mockCcmService, + HttpRequestSender.Factory senderFactory, + int numIsEnabledCalls + ) throws IOException { var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( eisGatewayUrl, threadPool, @@ -330,9 +331,9 @@ public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsAValidResponse_Whe webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson())); PlainActionFuture listener = new PlainActionFuture<>(); - authHandler.getAuthorizationSkippingIfCcmNotConfigured(listener, sender); + authHandler.getAuthorizationIfPermittedEnvironment(listener, sender); - var authResponse = listener.actionGet(TIMEOUT); + var authResponse = listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT); assertThat( authResponse.getTaskTypes(), is( @@ -357,23 +358,34 @@ public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsAValidResponse_Whe authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); verify(mockCcmFeature, times(1)).isCcmSupportedEnvironment(); - verify(mockCcmService, never()).isEnabled(any()); + verify(mockCcmService, times(numIsEnabledCalls)).isEnabled(any()); } } - public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsAValidResponse_WhenCcmSupportedEnvironmentAndConfigured() + public void testGetAuthorizationIfPermittedEnvironment_ReturnsAValidResponse_WhenCcmSupportedEnvironmentAndEnabled() throws IOException { var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); var eisGatewayUrl = getUrl(webServer); - var logger = mock(Logger.class); var mockCcmFeature = createMockCcmFeature(true); var mockCcmService = createMockCcmService(true); + assertReturnsValidResponse(eisGatewayUrl, mockCcmFeature, mockCcmService, senderFactory, 1); + } + + public void testGetAuthorizationIfPermittedEnvironment_ReturnsFailure_ForCcmSupportedEnvironment_WhenEnabledThrows() + throws IOException { + var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); + var eisGatewayUrl = getUrl(webServer); + + var mockCcmFeature = createMockCcmFeature(true); + + var exceptionToThrow = new IllegalStateException("exception"); + var mockCcmService = createMockCcmServiceWithOnFailureCall(exceptionToThrow); + var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( eisGatewayUrl, threadPool, - logger, createNoopApplierFactory(), mockCcmFeature, mockCcmService @@ -382,42 +394,25 @@ public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsAValidResponse_Whe try (var sender = senderFactory.createSender()) { var responseData = getEisAuthorizationResponseWithMultipleEndpoints(eisGatewayUrl); - webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson())); - PlainActionFuture listener = new PlainActionFuture<>(); - authHandler.getAuthorizationSkippingIfCcmNotConfigured(listener, sender); + authHandler.getAuthorizationIfPermittedEnvironment(listener, sender); - var authResponse = listener.actionGet(TIMEOUT); - assertThat( - authResponse.getTaskTypes(), - is( - EnumSet.of( - TaskType.CHAT_COMPLETION, - TaskType.SPARSE_EMBEDDING, - TaskType.TEXT_EMBEDDING, - TaskType.RERANK, - TaskType.COMPLETION - ) - ) - ); - assertThat(authResponse.getEndpointIds(), containsInAnyOrder(responseData.inferenceIds().toArray(String[]::new))); - assertTrue(authResponse.isAuthorized()); - assertThat( - authResponse.getEndpoints(responseData.inferenceIds()), - containsInAnyOrder(responseData.expectedEndpoints().toArray(ElasticInferenceServiceModel[]::new)) - ); + var authResponse = listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT); + assertThat(authResponse.getTaskTypes(), is(EnumSet.noneOf(TaskType.class))); + assertThat(authResponse.getEndpointIds(), empty()); + assertFalse(authResponse.isAuthorized()); + assertThat(authResponse.getEndpoints(responseData.inferenceIds()), empty()); - assertNoAuthHeader(webServer.requests()); + // There should be no requests made to EIS because it is not configured + assertThat(webServer.requests(), empty()); authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); verify(mockCcmFeature, times(1)).isCcmSupportedEnvironment(); - verify(mockCcmService, times(1)).isEnabled(any()); } } - public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsUnauthorized_WhenCcmSupportedEnvironmentAndNotConfigured() - throws IOException { + public void testGetAuthorizationIfPermittedEnvironment_ReturnsUnauthorized_WhenCcmSupportedEnvironmentAndDisabled() throws IOException { var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); var eisGatewayUrl = getUrl(webServer); var logger = mock(Logger.class); @@ -437,19 +432,17 @@ public void testGetAuthorizationSkipIfCcmNotConfigured_ReturnsUnauthorized_WhenC try (var sender = senderFactory.createSender()) { var responseData = getEisAuthorizationResponseWithMultipleEndpoints(eisGatewayUrl); - webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson())); - PlainActionFuture listener = new PlainActionFuture<>(); - authHandler.getAuthorizationSkippingIfCcmNotConfigured(listener, sender); + authHandler.getAuthorizationIfPermittedEnvironment(listener, sender); - var authResponse = listener.actionGet(TIMEOUT); + var authResponse = listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT); assertThat(authResponse.getTaskTypes(), is(EnumSet.noneOf(TaskType.class))); assertThat(authResponse.getEndpointIds(), empty()); assertFalse(authResponse.isAuthorized()); assertThat(authResponse.getEndpoints(responseData.inferenceIds()), empty()); // There should be no requests made to EIS because it is not configured - assertThat(webServer.requests().size(), is(0)); + assertThat(webServer.requests(), empty()); authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); @@ -481,7 +474,7 @@ public void testGetAuthorization_ReturnsAValidResponse_WithAuthHeader() throws I PlainActionFuture listener = new PlainActionFuture<>(); authHandler.getAuthorization(listener, sender); - var authResponse = listener.actionGet(TIMEOUT); + var authResponse = listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT); assertThat(authResponse.getTaskTypes(), is(EnumSet.of(TaskType.SPARSE_EMBEDDING))); assertThat(authResponse.getEndpointIds(), is(Set.of(ELSER_V2_ENDPOINT_ID))); @@ -524,9 +517,9 @@ public void testGetAuthorization_OnResponseCalledOnce() throws IOException { try (var sender = senderFactory.createSender()) { authHandler.getAuthorization(onlyOnceListener, sender); - authHandler.waitForAuthRequestCompletion(TIMEOUT); + authHandler.waitForAuthRequestCompletion(ESTestCase.TEST_REQUEST_TIMEOUT); - var authResponse = listener.actionGet(TIMEOUT); + var authResponse = listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT); assertThat(authResponse.getTaskTypes(), is(EnumSet.of(TaskType.SPARSE_EMBEDDING))); assertThat(authResponse.getEndpointIds(), is(Set.of(ELSER_V2_ENDPOINT_ID))); assertTrue(authResponse.isAuthorized()); @@ -565,7 +558,7 @@ public void testGetAuthorization_InvalidResponse() throws IOException { PlainActionFuture listener = new PlainActionFuture<>(); authHandler.getAuthorization(listener, sender); - var exception = expectThrows(ElasticsearchException.class, () -> listener.actionGet(TIMEOUT)); + var exception = expectThrows(ElasticsearchException.class, () -> listener.actionGet(ESTestCase.TEST_REQUEST_TIMEOUT)); assertThat(exception.getMessage(), containsString("Received an invalid response type from the Elastic Inference Service")); @@ -591,4 +584,14 @@ private static CCMService createMockCcmService(boolean isEnabled) { }).when(ccmService).isEnabled(any()); return ccmService; } + + private static CCMService createMockCcmServiceWithOnFailureCall(Exception exception) { + var ccmService = mock(CCMService.class); + doAnswer(invocation -> { + ActionListener listener = invocation.getArgument(0); + listener.onFailure(exception); + return Void.TYPE; + }).when(ccmService).isEnabled(any()); + return ccmService; + } } From fe509dae7bc5f5872d20784e5345138387b9b3e6 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Thu, 8 Jan 2026 16:13:37 -0500 Subject: [PATCH 3/4] Increasing log level --- .../ElasticInferenceServiceAuthorizationRequestHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java index baf05e0847f46..4598d01d30bed 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java @@ -127,13 +127,13 @@ private void getAuthorization( if (checkCcmState && ccmFeature.isCcmSupportedEnvironment()) { var isCcmEnabledListener = ActionListener.wrap(enabled -> { if (enabled == null || enabled == false) { - logger.debug("CCM is not enabled, skipping authorization request to Elastic Inference Service."); + logger.debug("CCM is not enabled, skipping authorization request to Elastic Inference Service"); countdownListener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); } else { retrieveAuthorizationInformation(countdownListener, sender); } }, e -> { - logger.atDebug().withThrowable(e).log("Failed to determine if CCM is configured, returning unauthorized."); + logger.atWarn().withThrowable(e).log("Failed to determine if CCM is enabled, returning unauthorized"); countdownListener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); }); @@ -142,7 +142,7 @@ private void getAuthorization( retrieveAuthorizationInformation(countdownListener, sender); } } catch (Exception e) { - logger.warn(Strings.format("Retrieving the authorization information encountered an exception: %s", e)); + logger.atWarn().withThrowable(e).log("Retrieving the authorization information encountered an exception"); countdownListener.onFailure(e); } } From 83f86fb0554d21df44d07fcd76ac6b834ec61264 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Thu, 8 Jan 2026 17:07:38 -0500 Subject: [PATCH 4/4] Fixing test --- ...ElasticInferenceServiceAuthorizationRequestHandlerTests.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java index 469c47359b215..3a81008c84c21 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandlerTests.java @@ -267,7 +267,6 @@ private static void assertNoAuthHeader(List requests) { public void testGetAuthorizationIfPermittedEnvironment_ReturnsFailure_WhenExceptionThrown() throws IOException { var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); var eisGatewayUrl = getUrl(webServer); - var logger = mock(Logger.class); var exceptionToThrow = new IllegalStateException("exception"); var mockCcmFeature = mock(CCMFeature.class); @@ -277,7 +276,6 @@ public void testGetAuthorizationIfPermittedEnvironment_ReturnsFailure_WhenExcept var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( eisGatewayUrl, threadPool, - logger, createNoopApplierFactory(), mockCcmFeature, mockCcmService