From 6c61bfcbec1810356832dc5ca8daa75cb4dec63b Mon Sep 17 00:00:00 2001 From: Terry Quigley Date: Fri, 22 May 2026 10:14:25 +0100 Subject: [PATCH 1/2] Allow audit config PUT when document does not exist Signed-off-by: Terry Quigley --- .../dlic/rest/api/AuditApiAction.java | 14 +++++++++- .../api/AuditApiActionValidationTest.java | 26 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AuditApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AuditApiAction.java index 20092e26b4..a03b87c20e 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AuditApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AuditApiAction.java @@ -267,12 +267,24 @@ private void auditApiRequestHandlers(RequestHandler.RequestHandlersBuilder reque .onChangeRequest(RestRequest.Method.PATCH, request -> withEnabledAuditApi(request).map(this::processPatchRequest)) .onChangeRequest( RestRequest.Method.PUT, - request -> withEnabledAuditApi(request).map(ignore -> processPutRequest("config", request)) + request -> withCreateOrUpdateAuditApi(request).map(ignore -> processPutRequest("config", request)) ) .override(RestRequest.Method.POST, methodNotImplementedHandler) .override(RestRequest.Method.DELETE, methodNotImplementedHandler); } + /** + * Allows PUT to bootstrap the audit config when the document does not exist, + * or to update it through normal validation when it does. + */ + ValidationResult withCreateOrUpdateAuditApi(final RestRequest request) { + if (!securityApiDependencies.configurationRepository().isAuditHotReloadingEnabled()) { + // Document does not exist — allow PUT to bootstrap the audit config + return ValidationResult.success(request); + } + return withEnabledAuditApi(request); + } + ValidationResult withEnabledAuditApi(final RestRequest request) { if (!securityApiDependencies.configurationRepository().isAuditHotReloadingEnabled()) { return ValidationResult.error(RestStatus.NOT_IMPLEMENTED, methodNotImplementedMessage(request.method())); diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionValidationTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionValidationTest.java index 7bf40994bd..ff241bd2af 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionValidationTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionValidationTest.java @@ -12,11 +12,13 @@ package org.opensearch.security.dlic.rest.api; import java.util.List; +import java.util.Set; import org.junit.Test; import org.opensearch.common.settings.Settings; import org.opensearch.core.rest.RestStatus; +import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; @@ -42,6 +44,30 @@ public void disabledAuditApi() { } } + @Test + public void putAllowedWhenAuditConfigDocDoesNotExist() { + final var auditApiAction = new AuditApiAction(clusterService, threadPool, securityApiDependencies); + when(configurationRepository.isAuditHotReloadingEnabled()).thenReturn(false); + + // PUT is allowed when the audit config document does not exist (bootstrap case) + final var result = auditApiAction.withCreateOrUpdateAuditApi( + FakeRestRequest.builder().withMethod(RestRequest.Method.PUT).build() + ); + assertTrue(result.isValid()); + } + + @Test + public void putAllowedWhenAuditConfigDocExists() { + final var auditApiAction = new AuditApiAction(clusterService, threadPool, securityApiDependencies); + when(configurationRepository.isAuditHotReloadingEnabled()).thenReturn(true); + + // PUT is also allowed when the audit config document exists (update case) + final var result = auditApiAction.withCreateOrUpdateAuditApi( + FakeRestRequest.builder().withMethod(RestRequest.Method.PUT).build() + ); + assertTrue(result.isValid()); + } + @Test public void enabledAuditApi() { final var auditApiAction = new AuditApiAction(clusterService, threadPool, securityApiDependencies); From 85cdad3b9cb9255d565b12c7d13e9e41c340c649 Mon Sep 17 00:00:00 2001 From: Terry Quigley Date: Fri, 22 May 2026 14:11:25 +0100 Subject: [PATCH 2/2] spotless Signed-off-by: Terry Quigley --- .../dlic/rest/api/AuditApiActionValidationTest.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionValidationTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionValidationTest.java index ff241bd2af..7897406054 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionValidationTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionValidationTest.java @@ -12,7 +12,6 @@ package org.opensearch.security.dlic.rest.api; import java.util.List; -import java.util.Set; import org.junit.Test; @@ -50,9 +49,7 @@ public void putAllowedWhenAuditConfigDocDoesNotExist() { when(configurationRepository.isAuditHotReloadingEnabled()).thenReturn(false); // PUT is allowed when the audit config document does not exist (bootstrap case) - final var result = auditApiAction.withCreateOrUpdateAuditApi( - FakeRestRequest.builder().withMethod(RestRequest.Method.PUT).build() - ); + final var result = auditApiAction.withCreateOrUpdateAuditApi(FakeRestRequest.builder().withMethod(RestRequest.Method.PUT).build()); assertTrue(result.isValid()); } @@ -62,9 +59,7 @@ public void putAllowedWhenAuditConfigDocExists() { when(configurationRepository.isAuditHotReloadingEnabled()).thenReturn(true); // PUT is also allowed when the audit config document exists (update case) - final var result = auditApiAction.withCreateOrUpdateAuditApi( - FakeRestRequest.builder().withMethod(RestRequest.Method.PUT).build() - ); + final var result = auditApiAction.withCreateOrUpdateAuditApi(FakeRestRequest.builder().withMethod(RestRequest.Method.PUT).build()); assertTrue(result.isValid()); }