From 75d62d7dc17423a2f5017847f9f24a943a925f4e Mon Sep 17 00:00:00 2001 From: mdayican Date: Wed, 18 Mar 2026 18:04:57 +0000 Subject: [PATCH 1/6] EM-7028 pass role to dm-store --- .../DmStoreDownloaderIntegrationTest.java | 24 +++++++++--- .../batch/DocumentTaskItemProcessor.java | 2 +- .../stitching/service/DmStoreDownloader.java | 2 +- .../service/impl/DmStoreDownloaderImpl.java | 29 +++++++++++---- .../service/impl/DmStoreUploaderImpl.java | 21 +++++++---- .../batch/DocumentTaskItemProcessorTest.java | 13 ++++--- .../impl/DmStoreDownloaderImplTest.java | 37 +++++++++++++------ .../service/impl/DmStoreUploaderImplTest.java | 2 + 8 files changed, 89 insertions(+), 41 deletions(-) diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderIntegrationTest.java b/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderIntegrationTest.java index 0c8641d67..9b56238ab 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderIntegrationTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderIntegrationTest.java @@ -20,6 +20,8 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean; import uk.gov.hmcts.reform.authorisation.generators.AuthTokenGenerator; import uk.gov.hmcts.reform.em.stitching.domain.BundleDocument; +import uk.gov.hmcts.reform.idam.client.IdamClient; +import uk.gov.hmcts.reform.idam.client.models.UserInfo; import java.io.IOException; import java.util.List; @@ -29,6 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @SpringBootTest @@ -45,6 +48,7 @@ class DmStoreDownloaderIntegrationTest { private String mockServerBaseUrl; private final OkHttpClient okHttpClient = new OkHttpClient(); + private static final String TEST_JWT = "test-jwt"; private static final String JSON_TYPE = "application/json"; private static final String PDF_TYPE = "application/pdf"; @@ -55,7 +59,15 @@ void setUp() throws IOException { mockServerBaseUrl = "http://localhost:" + mockWebServer.getPort(); DmStoreUriFormatter formatter = new DmStoreUriFormatter(mockServerBaseUrl); - dmStoreDownloader = new DmStoreDownloaderImpl(okHttpClient, authTokenGenerator, formatter, objectMapper); + + IdamClient idamClient = mock(IdamClient.class); + UserInfo userInfo = mock(UserInfo.class); + when(idamClient.getUserInfo(TEST_JWT)).thenReturn(userInfo); + when(userInfo.getUid()).thenReturn("test-user-id"); + when(userInfo.getRoles()).thenReturn(List.of("caseworker-ia", "caseworker")); + + dmStoreDownloader = new DmStoreDownloaderImpl( + okHttpClient, authTokenGenerator, formatter, objectMapper, idamClient); when(authTokenGenerator.generate()).thenReturn("Bearer test-token"); } @@ -76,7 +88,7 @@ void shouldReconstructCleanUrl() throws Exception { BundleDocument doc = createBundleDoc("https://external-system.com:8443/documents/" + docId); enqueueDoc(docId); - dmStoreDownloader.downloadFiles(Stream.of(doc)).toList(); + dmStoreDownloader.downloadFiles(Stream.of(doc), TEST_JWT).toList(); assertRequestMatches(mockWebServer.takeRequest(), "/documents/" + docId); } @@ -93,7 +105,7 @@ void shouldHandleMixedFormatsInParallel() throws Exception { createBundleDoc(docId.toString()) ); - dmStoreDownloader.downloadFiles(docs).toList(); + dmStoreDownloader.downloadFiles(docs, TEST_JWT).toList(); for (int i = 0; i < 6; i++) { assertThat(mockWebServer.takeRequest().getUrl().toString()).contains(docId.toString()); @@ -109,7 +121,7 @@ void shouldSanitizeInternalMetadataLinks() throws Exception { mockWebServer.enqueue(jsonResponse(dirtyMetadata)); mockWebServer.enqueue(binaryResponse()); - dmStoreDownloader.downloadFiles(Stream.of(createBundleDoc(docId.toString()))).toList(); + dmStoreDownloader.downloadFiles(Stream.of(createBundleDoc(docId.toString())), TEST_JWT).toList(); mockWebServer.takeRequest(); // Skip metadata RecordedRequest binaryReq = mockWebServer.takeRequest(); @@ -130,7 +142,7 @@ void shouldDownloadAndReturnFileWithMediaType() throws Exception { enqueueDoc(docId); List> results = - dmStoreDownloader.downloadFiles(Stream.of(createBundleDoc(docId.toString()))).toList(); + dmStoreDownloader.downloadFiles(Stream.of(createBundleDoc(docId.toString())), TEST_JWT).toList(); assertThat(results).hasSize(1); Pair result = results.get(0); @@ -162,7 +174,7 @@ void shouldRejectInvalidInputs(String input) { BundleDocument doc = createBundleDoc(finalInput); - assertThatThrownBy(() -> dmStoreDownloader.downloadFiles(Stream.of(doc)).toList()) + assertThatThrownBy(() -> dmStoreDownloader.downloadFiles(Stream.of(doc), TEST_JWT).toList()) .hasRootCauseInstanceOf(IllegalArgumentException.class); assertThat(mockWebServer.getRequestCount()).isZero(); diff --git a/src/main/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessor.java b/src/main/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessor.java index 5a66cb7d7..48e98a86a 100644 --- a/src/main/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessor.java +++ b/src/main/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessor.java @@ -130,7 +130,7 @@ public DocumentTask process(DocumentTask documentTask) { log.info("Documents uploaded through CDAM for DocumentTask Id : #{} ", documentTask.getId()); } else { bundleFiles = dmStoreDownloader - .downloadFiles(documentTask.getBundle().getSortedDocuments()) + .downloadFiles(documentTask.getBundle().getSortedDocuments(), documentTask.getJwt()) .map(documentConverter::convert) .map(file -> pdfWatermark.processDocumentWatermark( documentImage, file, diff --git a/src/main/java/uk/gov/hmcts/reform/em/stitching/service/DmStoreDownloader.java b/src/main/java/uk/gov/hmcts/reform/em/stitching/service/DmStoreDownloader.java index 041a2654f..4c038480e 100644 --- a/src/main/java/uk/gov/hmcts/reform/em/stitching/service/DmStoreDownloader.java +++ b/src/main/java/uk/gov/hmcts/reform/em/stitching/service/DmStoreDownloader.java @@ -8,5 +8,5 @@ public interface DmStoreDownloader { - Stream> downloadFiles(Stream bundleDocuments); + Stream> downloadFiles(Stream bundleDocuments, String jwt); } diff --git a/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImpl.java b/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImpl.java index 111a5569e..a4ef41d16 100644 --- a/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImpl.java +++ b/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImpl.java @@ -13,6 +13,8 @@ import uk.gov.hmcts.reform.authorisation.generators.AuthTokenGenerator; import uk.gov.hmcts.reform.em.stitching.domain.BundleDocument; import uk.gov.hmcts.reform.em.stitching.service.DmStoreDownloader; +import uk.gov.hmcts.reform.idam.client.IdamClient; +import uk.gov.hmcts.reform.idam.client.models.UserInfo; import java.io.File; import java.io.IOException; @@ -36,30 +38,39 @@ public class DmStoreDownloaderImpl implements DmStoreDownloader { private final ObjectMapper objectMapper; + private final IdamClient idamClient; + public DmStoreDownloaderImpl(OkHttpClient okHttpClient, AuthTokenGenerator authTokenGenerator, DmStoreUriFormatter dmStoreUriFormatter, - ObjectMapper objectMapper) { + ObjectMapper objectMapper, + IdamClient idamClient) { this.okHttpClient = okHttpClient; this.authTokenGenerator = authTokenGenerator; this.dmStoreUriFormatter = dmStoreUriFormatter; this.objectMapper = objectMapper; + this.idamClient = idamClient; } @Override - public Stream> downloadFiles(Stream bundleDocuments) { + public Stream> downloadFiles(Stream bundleDocuments, + String jwt) { + UserInfo userInfo = idamClient.getUserInfo(jwt); + String userId = userInfo.getUid(); + String userRoles = String.join(",", userInfo.getRoles()); return bundleDocuments .parallel() - .map(unchecked(this::downloadFile)); + .map(unchecked(bundleDocument -> downloadFile(bundleDocument, userId, userRoles))); } - private Pair downloadFile(BundleDocument bundleDocument) + private Pair downloadFile(BundleDocument bundleDocument, + String userId, String userRoles) throws DocumentTaskProcessingException { Response getDocumentMetaDataResponse = null; Response getDocumentContentResponse = null; try { - getDocumentMetaDataResponse = getDocumentStoreResponse(bundleDocument.getDocumentURI()); + getDocumentMetaDataResponse = getDocumentStoreResponse(bundleDocument.getDocumentURI(), userId, userRoles); if (getDocumentMetaDataResponse.isSuccessful()) { @@ -69,7 +80,7 @@ private Pair downloadFile(BundleDocument bundl log.debug("Accessing documentBinaryUrl: {}", documentBinaryUrl); - getDocumentContentResponse = getDocumentStoreResponse(documentBinaryUrl); + getDocumentContentResponse = getDocumentStoreResponse(documentBinaryUrl, userId, userRoles); if (getDocumentContentResponse.isSuccessful()) { return Pair.of(bundleDocument, @@ -93,14 +104,16 @@ private Pair downloadFile(BundleDocument bundl } } - private Response getDocumentStoreResponse(String documentUri) throws IOException { + private Response getDocumentStoreResponse(String documentUri, String userId, String userRoles) + throws IOException { String fixedUrl = dmStoreUriFormatter.formatDmStoreUri(documentUri); log.debug("getDocumentStoreResponse - URL: {}", fixedUrl); return okHttpClient.newCall(new Request.Builder() - .addHeader("user-roles", "caseworker") + .addHeader("user-id", userId) + .addHeader("user-roles", userRoles) .addHeader("ServiceAuthorization", authTokenGenerator.generate()) .url(fixedUrl) .build()).execute(); diff --git a/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImpl.java b/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImpl.java index 0f162f345..d782ed279 100644 --- a/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImpl.java +++ b/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImpl.java @@ -16,6 +16,7 @@ import uk.gov.hmcts.reform.em.stitching.service.DmStoreUploader; import uk.gov.hmcts.reform.em.stitching.service.StringFormattingUtils; import uk.gov.hmcts.reform.idam.client.IdamClient; +import uk.gov.hmcts.reform.idam.client.models.UserInfo; import java.io.File; import java.io.IOException; @@ -72,9 +73,13 @@ private void uploadNewDocument(File file, DocumentTask documentTask) throws Docu ) .build(); + UserInfo userInfo = idamClient.getUserInfo(documentTask.getJwt()); + String userId = userInfo.getUid(); + String userRoles = String.join(",", userInfo.getRoles()); + Request request = new Request.Builder() - .addHeader("user-id", getUserId(documentTask)) - .addHeader("user-roles", "caseworker") + .addHeader("user-id", userId) + .addHeader("user-roles", userRoles) .addHeader("ServiceAuthorization", authTokenGenerator.generate()) .url(dmStoreAppBaseUrl + ENDPOINT) .method("POST", requestBody) @@ -122,9 +127,13 @@ private void uploadNewDocumentVersion(File file, DocumentTask documentTask) thro RequestBody.create(file, MediaType.get("application/pdf"))) .build(); + UserInfo userInfo = idamClient.getUserInfo(documentTask.getJwt()); + String userId = userInfo.getUid(); + String userRoles = String.join(",", userInfo.getRoles()); + Request request = new Request.Builder() - .addHeader("user-id", getUserId(documentTask)) - .addHeader("user-roles", "caseworker") + .addHeader("user-id", userId) + .addHeader("user-roles", userRoles) .addHeader("ServiceAuthorization", authTokenGenerator.generate()) .url(documentTask.getBundle().getStitchedDocumentURI()) .method("POST", requestBody) @@ -143,8 +152,4 @@ private void uploadNewDocumentVersion(File file, DocumentTask documentTask) thro } } - private String getUserId(DocumentTask documentTask) { - return idamClient.getUserInfo(documentTask.getJwt()).getUid(); - } - } diff --git a/src/test/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessorTest.java b/src/test/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessorTest.java index cc47cd210..1f60ddc5f 100644 --- a/src/test/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessorTest.java +++ b/src/test/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessorTest.java @@ -38,6 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.lenient; @@ -136,7 +137,7 @@ void usesCoverPageRender() throws IOException, DocumentTaskProcessingException { Pair convertedMockPair = Pair.of(testBundle.getDocuments().getFirst(), file); - when(dmStoreDownloader.downloadFiles(any())).thenReturn(Stream.of(mockPair)); + when(dmStoreDownloader.downloadFiles(any(), anyString())).thenReturn(Stream.of(mockPair)); when(documentConverter.convert(any())).thenReturn(convertedMockPair); when(docmosisClient.renderDocmosisTemplate(COVER_PAGE_TEMPLATE, coverPageData)).thenReturn(coverPageFile); @@ -151,7 +152,7 @@ void testFailure() { documentTask.setBundle(BundleTest.getTestBundle()); Mockito - .when(dmStoreDownloader.downloadFiles(any())) + .when(dmStoreDownloader.downloadFiles(any(), anyString())) .thenThrow(new WrappedException(new DocumentTaskProcessingException("problem"))); itemProcessor.process(documentTask); @@ -179,7 +180,7 @@ void testStitch() throws DocumentTaskProcessingException { Pair convertedMockPair2 = Pair.of(documentTask.getBundle().getDocuments().get(1), file); Mockito - .when(dmStoreDownloader.downloadFiles(any())) + .when(dmStoreDownloader.downloadFiles(any(), anyString())) .thenReturn(files); Mockito @@ -290,7 +291,7 @@ void testStitchDocumentImageNull() throws DocumentTaskProcessingException { Pair convertedMockPair2 = Pair.of(documentTask.getBundle().getDocuments().get(1), file); Mockito - .when(dmStoreDownloader.downloadFiles(any())) + .when(dmStoreDownloader.downloadFiles(any(), anyString())) .thenReturn(files); Mockito @@ -345,7 +346,7 @@ void testStitchDocumentImageAssetIdNull() throws DocumentTaskProcessingException Pair convertedMockPair2 = Pair.of(documentTask.getBundle().getDocuments().get(1), file); Mockito - .when(dmStoreDownloader.downloadFiles(any())) + .when(dmStoreDownloader.downloadFiles(any(), anyString())) .thenReturn(files); Mockito @@ -392,7 +393,7 @@ void testProcessWhenTaskAlreadyInProgressReturnsNull() { DocumentTask result = itemProcessor.process(documentTask); assertNull(result); - verify(dmStoreDownloader, never()).downloadFiles(any()); + verify(dmStoreDownloader, never()).downloadFiles(any(), anyString()); verify(cdamService, never()).downloadFiles(any()); } diff --git a/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImplTest.java b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImplTest.java index c59d671f6..5fcbf8d46 100644 --- a/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImplTest.java +++ b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImplTest.java @@ -17,11 +17,14 @@ import pl.touk.throwing.exception.WrappedException; import uk.gov.hmcts.reform.em.stitching.domain.BundleDocument; import uk.gov.hmcts.reform.em.stitching.service.DmStoreDownloader; +import uk.gov.hmcts.reform.idam.client.IdamClient; +import uk.gov.hmcts.reform.idam.client.models.UserInfo; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; +import java.util.List; import java.util.Objects; import java.util.stream.Stream; @@ -30,7 +33,9 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -53,6 +58,9 @@ class DmStoreDownloaderImplTest { @Mock private DmStoreUriFormatter dmStoreUriFormatter; + private IdamClient idamClient; + private static final String TEST_JWT = "test-jwt"; + private int metadataResponseCode; private int binaryResponseCode; private String metadataResponseBody; @@ -85,7 +93,14 @@ void setup() { return DUMMY_DM_STORE_BASE_URL + (originalUri.startsWith("/") ? originalUri : "/" + originalUri); }); - dmStoreDownloader = new DmStoreDownloaderImpl(http, () -> "auth", dmStoreUriFormatter, new ObjectMapper()); + idamClient = mock(IdamClient.class); + UserInfo userInfo = mock(UserInfo.class); + when(idamClient.getUserInfo(anyString())).thenReturn(userInfo); + when(userInfo.getUid()).thenReturn("mockUserId"); + when(userInfo.getRoles()).thenReturn(List.of("caseworker-ia", "caseworker")); + + dmStoreDownloader = new DmStoreDownloaderImpl( + http, () -> "auth", dmStoreUriFormatter, new ObjectMapper(), idamClient); } private Response intercept(Interceptor.Chain chain) throws IOException { @@ -150,7 +165,7 @@ void downloadFiles() { mockBundleDocument2.setDocumentURI("/BBBB"); Stream> resultsStream = - dmStoreDownloader.downloadFiles(Stream.of(mockBundleDocument1, mockBundleDocument2)); + dmStoreDownloader.downloadFiles(Stream.of(mockBundleDocument1, mockBundleDocument2), TEST_JWT); assertNotNull(resultsStream); assertEquals(2, resultsStream.toList().size()); } @@ -161,7 +176,7 @@ void downloadFileCreatesTempFileAndReturnsCorrectMediaType() throws IOException mockBundleDocument1.setDocumentURI("/AAAA"); Stream> resultsStream = - dmStoreDownloader.downloadFiles(Stream.of(mockBundleDocument1)); + dmStoreDownloader.downloadFiles(Stream.of(mockBundleDocument1), TEST_JWT); Pair result = resultsStream.toList().getFirst(); assertEquals(mockBundleDocument1, result.getFirst()); @@ -178,7 +193,7 @@ void downloadFileWhenDocumentUriIsNull() { docWithNullUri.setDocumentURI(null); DocumentTaskProcessingException actualException = assertAndGetCause( - () -> dmStoreDownloader.downloadFiles(Stream.of(docWithNullUri)).toList() + () -> dmStoreDownloader.downloadFiles(Stream.of(docWithNullUri), TEST_JWT).toList() ); assertEquals("Could not access the binary: Original URI cannot be null for DmStoreUriFormatter", actualException.getMessage()); @@ -195,7 +210,7 @@ void downloadFileWhenMetadataRequestFails() { doc.setDocumentURI("/docPath1"); DocumentTaskProcessingException actualException = assertAndGetCause( - () -> dmStoreDownloader.downloadFiles(Stream.of(doc)).toList() + () -> dmStoreDownloader.downloadFiles(Stream.of(doc), TEST_JWT).toList() ); assertTrue(actualException.getMessage().contains("Could not access the meta-data. HTTP response: 500")); } @@ -207,7 +222,7 @@ void downloadFileWhenBinaryRequestFails() { doc.setDocumentURI("/docPath2"); DocumentTaskProcessingException actualException = assertAndGetCause( - () -> dmStoreDownloader.downloadFiles(Stream.of(doc)).toList() + () -> dmStoreDownloader.downloadFiles(Stream.of(doc), TEST_JWT).toList() ); assertTrue(actualException.getMessage().contains("Could not access the binary. HTTP response: 404")); } @@ -219,7 +234,7 @@ void downloadFileWhenMetadataIsMalformed() { doc.setDocumentURI("/docPath3"); DocumentTaskProcessingException actualException = assertAndGetCause( - () -> dmStoreDownloader.downloadFiles(Stream.of(doc)).toList() + () -> dmStoreDownloader.downloadFiles(Stream.of(doc), TEST_JWT).toList() ); assertTrue(actualException.getMessage().startsWith("Could not access the binary: Unrecognized token 'this'")); assertNotNull(actualException.getCause()); @@ -234,7 +249,7 @@ void downloadFileWhenMetadataIsIncomplete() { doc.setDocumentURI("/docPath4"); DocumentTaskProcessingException actualException = assertAndGetCause( - () -> dmStoreDownloader.downloadFiles(Stream.of(doc)).toList() + () -> dmStoreDownloader.downloadFiles(Stream.of(doc), TEST_JWT).toList() ); String expectedNpeMessage = "Cannot invoke \"com.fasterxml.jackson.databind.JsonNode.get(String)\" " + "because the return value of \"com.fasterxml.jackson.databind.JsonNode.get(String)\" is null"; @@ -255,7 +270,7 @@ void downloadFileWhenMetadataIsIncompleteMissingHrefNode() { doc.setDocumentURI("/docPath5"); DocumentTaskProcessingException actualException = assertAndGetCause( - () -> dmStoreDownloader.downloadFiles(Stream.of(doc)).toList() + () -> dmStoreDownloader.downloadFiles(Stream.of(doc), TEST_JWT).toList() ); String expectedNpeMessage = "Cannot invoke \"com.fasterxml.jackson.databind.JsonNode.asText()\" " + "because the return value of \"com.fasterxml.jackson.databind.JsonNode.get(String)\" is null"; @@ -273,7 +288,7 @@ void downloadFileWhenMetadataCallThrowsIOException() { doc.setDocumentURI("/docPath6"); DocumentTaskProcessingException actualException = assertAndGetCause( - () -> dmStoreDownloader.downloadFiles(Stream.of(doc)).toList() + () -> dmStoreDownloader.downloadFiles(Stream.of(doc), TEST_JWT).toList() ); assertTrue(actualException.getMessage() .contains("Could not access the binary: Simulated IOException for metadata request")); @@ -289,7 +304,7 @@ void downloadFileWhenBinaryCallThrowsIOException() { doc.setDocumentURI("/docPath7"); DocumentTaskProcessingException actualException = assertAndGetCause( - () -> dmStoreDownloader.downloadFiles(Stream.of(doc)).toList() + () -> dmStoreDownloader.downloadFiles(Stream.of(doc), TEST_JWT).toList() ); assertTrue(actualException.getMessage() .contains("Could not access the binary: Simulated IOException for binary request")); diff --git a/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImplTest.java b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImplTest.java index 52c2dd651..028ed4d2c 100644 --- a/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImplTest.java +++ b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImplTest.java @@ -24,6 +24,7 @@ import java.io.File; import java.io.IOException; +import java.util.List; import java.util.function.Consumer; import java.util.stream.Stream; @@ -58,6 +59,7 @@ void setup() { UserInfo userInfo = mock(UserInfo.class); when(idamClient.getUserInfo(anyString())).thenReturn(userInfo); when(userInfo.getUid()).thenReturn("mockUserId"); + when(userInfo.getRoles()).thenReturn(List.of("caseworker-ia", "caseworker")); dmStoreUploader = new DmStoreUploaderImpl( okHttpClient, From ccdca816cc771040738678d19295b216bd2f8939 Mon Sep 17 00:00:00 2001 From: mdayican Date: Wed, 18 Mar 2026 18:33:54 +0000 Subject: [PATCH 2/6] fix style --- .../service/impl/DmStoreDownloaderIntegrationTest.java | 4 ++-- .../em/stitching/batch/DocumentTaskItemProcessorTest.java | 5 +++++ .../stitching/service/impl/DmStoreDownloaderImplTest.java | 8 ++++---- .../stitching/service/impl/DmStoreUploaderImplTest.java | 8 ++++---- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderIntegrationTest.java b/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderIntegrationTest.java index 9b56238ab..4a036a36f 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderIntegrationTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderIntegrationTest.java @@ -58,14 +58,14 @@ void setUp() throws IOException { mockWebServer.start(); mockServerBaseUrl = "http://localhost:" + mockWebServer.getPort(); - DmStoreUriFormatter formatter = new DmStoreUriFormatter(mockServerBaseUrl); - IdamClient idamClient = mock(IdamClient.class); UserInfo userInfo = mock(UserInfo.class); when(idamClient.getUserInfo(TEST_JWT)).thenReturn(userInfo); when(userInfo.getUid()).thenReturn("test-user-id"); when(userInfo.getRoles()).thenReturn(List.of("caseworker-ia", "caseworker")); + DmStoreUriFormatter formatter = new DmStoreUriFormatter(mockServerBaseUrl); + dmStoreDownloader = new DmStoreDownloaderImpl( okHttpClient, authTokenGenerator, formatter, objectMapper, idamClient); diff --git a/src/test/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessorTest.java b/src/test/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessorTest.java index 1f60ddc5f..077d4e0e6 100644 --- a/src/test/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessorTest.java +++ b/src/test/java/uk/gov/hmcts/reform/em/stitching/batch/DocumentTaskItemProcessorTest.java @@ -126,6 +126,7 @@ void usesCoverPageRender() throws IOException, DocumentTaskProcessingException { testBundle.setCoverpageTemplateData(coverPageData); documentTaskWithCoversheet.setBundle(testBundle); + documentTaskWithCoversheet.setJwt("mockJwt"); URL url = ClassLoader.getSystemResource(PDF_FILENAME); @@ -150,6 +151,7 @@ void usesCoverPageRender() throws IOException, DocumentTaskProcessingException { void testFailure() { DocumentTask documentTask = new DocumentTask(); documentTask.setBundle(BundleTest.getTestBundle()); + documentTask.setJwt("mockJwt"); Mockito .when(dmStoreDownloader.downloadFiles(any(), anyString())) @@ -165,6 +167,7 @@ void testFailure() { void testStitch() throws DocumentTaskProcessingException { DocumentTask documentTask = new DocumentTask(); documentTask.setBundle(BundleTest.getTestBundle()); + documentTask.setJwt("mockJwt"); File file = mock(File.class); @@ -275,6 +278,7 @@ void testCdamStitch() throws DocumentTaskProcessingException { void testStitchDocumentImageNull() throws DocumentTaskProcessingException { DocumentTask documentTask = new DocumentTask(); documentTask.setBundle(BundleTest.getTestBundle()); + documentTask.setJwt("mockJwt"); documentTask.getBundle().setDocumentImage(null); File file = mock(File.class); @@ -330,6 +334,7 @@ void testStitchDocumentImageNull() throws DocumentTaskProcessingException { void testStitchDocumentImageAssetIdNull() throws DocumentTaskProcessingException { DocumentTask documentTask = new DocumentTask(); documentTask.setBundle(BundleTest.getTestBundle()); + documentTask.setJwt("mockJwt"); documentTask.getBundle().getDocumentImage().setDocmosisAssetId(null); File file = mock(File.class); diff --git a/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImplTest.java b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImplTest.java index 5fcbf8d46..2b1affff8 100644 --- a/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImplTest.java +++ b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreDownloaderImplTest.java @@ -77,10 +77,6 @@ void setup() { this.throwIOExceptionForBinary = false; this.useEmptyBinaryResponseBody = false; - OkHttpClient http = new OkHttpClient - .Builder() - .addInterceptor(this::intercept) - .build(); when(dmStoreUriFormatter.formatDmStoreUri(nullable(String.class))).thenAnswer(invocation -> { String originalUri = invocation.getArgument(0); @@ -99,6 +95,10 @@ void setup() { when(userInfo.getUid()).thenReturn("mockUserId"); when(userInfo.getRoles()).thenReturn(List.of("caseworker-ia", "caseworker")); + OkHttpClient http = new OkHttpClient + .Builder() + .addInterceptor(this::intercept) + .build(); dmStoreDownloader = new DmStoreDownloaderImpl( http, () -> "auth", dmStoreUriFormatter, new ObjectMapper(), idamClient); } diff --git a/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImplTest.java b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImplTest.java index 028ed4d2c..881d9b474 100644 --- a/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImplTest.java +++ b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DmStoreUploaderImplTest.java @@ -51,16 +51,16 @@ void setup() { throwIOExceptionInInterceptor = false; responseBodyContent = "{ _embedded: { documents: [ { _links: { self: { href: 'docUri' } } } ] } }"; - OkHttpClient okHttpClient = new OkHttpClient.Builder() - .addInterceptor(this::intercept) - .build(); - IdamClient idamClient = mock(IdamClient.class); UserInfo userInfo = mock(UserInfo.class); when(idamClient.getUserInfo(anyString())).thenReturn(userInfo); when(userInfo.getUid()).thenReturn("mockUserId"); when(userInfo.getRoles()).thenReturn(List.of("caseworker-ia", "caseworker")); + + OkHttpClient okHttpClient = new OkHttpClient.Builder() + .addInterceptor(this::intercept) + .build(); dmStoreUploader = new DmStoreUploaderImpl( okHttpClient, () -> "mocked-s2s-token", From a4e7dffdbbb42c6412a0407ffcb948e1a65b42d6 Mon Sep 17 00:00:00 2001 From: mdayican Date: Thu, 19 Mar 2026 09:05:10 +0000 Subject: [PATCH 3/6] add functional test --- .../DocumentTaskAuthorizationScenarios.java | 81 +++++++++++++++++++ .../em/stitching/testutil/TestUtil.java | 4 + 2 files changed, 85 insertions(+) create mode 100644 src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java diff --git a/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java b/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java new file mode 100644 index 000000000..a004c8c01 --- /dev/null +++ b/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java @@ -0,0 +1,81 @@ +package uk.gov.hmcts.reform.em.stitching.functional; + +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import net.serenitybdd.rest.SerenityRest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import uk.gov.hmcts.reform.em.stitching.service.dto.BundleDTO; +import uk.gov.hmcts.reform.em.stitching.service.dto.DocumentTaskDTO; +import uk.gov.hmcts.reform.em.stitching.testutil.TestUtil; +import uk.gov.hmcts.reform.em.test.idam.IdamHelper; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static uk.gov.hmcts.reform.em.stitching.testutil.TestDataConstants.AUTH_HEADER; +import static uk.gov.hmcts.reform.em.stitching.testutil.TestDataConstants.SERVICE_AUTH_HEADER; +import static uk.gov.hmcts.reform.em.stitching.testutil.TestDataConstants.TASK_STATE_FIELD; +import static uk.gov.hmcts.reform.em.stitching.testutil.TestUtil.convertObjectToJsonBytes; + +class DocumentTaskAuthorizationScenarios extends BaseTest { + + private static final String DOCUMENT_TASKS_ENDPOINT = "/api/document-tasks"; + private static final List NON_CASEWORKER_ROLES = List.of("ccd-import"); + + private final IdamHelper idamHelper; + private final String nonCaseworkerEmail = + "stitching.citizen." + UUID.randomUUID() + "@test.com"; + + private RequestSpecification nonCaseworkerRequest; + + @Autowired + DocumentTaskAuthorizationScenarios(TestUtil testUtil, IdamHelper idamHelper) { + super(testUtil); + this.idamHelper = idamHelper; + } + + @BeforeEach + void setupNonCaseworkerUser() { + idamHelper.createUser(nonCaseworkerEmail, NON_CASEWORKER_ROLES); + String nonCaseworkerJwt = idamHelper.authenticateUser(nonCaseworkerEmail); + + nonCaseworkerRequest = SerenityRest + .given() + .baseUri(testUtil.getTestUrl()) + .contentType(APPLICATION_JSON_VALUE) + .header(AUTH_HEADER, nonCaseworkerJwt) + .header(SERVICE_AUTH_HEADER, testUtil.getS2sAuth()); + } + + @Test + void shouldFailTaskWhenUserHasNoCaseworkerRole() throws IOException, InterruptedException { + BundleDTO bundle = testUtil.getTestBundle(); + DocumentTaskDTO documentTask = new DocumentTaskDTO(); + documentTask.setBundle(bundle); + + Response createTaskResponse = nonCaseworkerRequest + .body(convertObjectToJsonBytes(documentTask)) + .post(DOCUMENT_TASKS_ENDPOINT); + + assertEquals(201, createTaskResponse.getStatusCode(), + "Task creation should be accepted regardless of role; " + + "authorisation is enforced when downloading from DM Store."); + + String taskUrl = DOCUMENT_TASKS_ENDPOINT + "/" + + createTaskResponse.getBody().jsonPath().getString("id"); + + Response taskResponse = testUtil.pollUntil(taskUrl, body -> { + String state = body.getString(TASK_STATE_FIELD); + return "FAILED".equals(state) || "DONE".equals(state); + }); + + assertEquals("FAILED", taskResponse.getBody().jsonPath().getString(TASK_STATE_FIELD), + "Task should have FAILED because DM Store rejects downloads for non-caseworker roles. " + + "If DONE, the hardcoded 'caseworker' role has been reintroduced."); + } +} diff --git a/src/aat/java/uk/gov/hmcts/reform/em/stitching/testutil/TestUtil.java b/src/aat/java/uk/gov/hmcts/reform/em/stitching/testutil/TestUtil.java index 642aa92f2..1d15eb682 100644 --- a/src/aat/java/uk/gov/hmcts/reform/em/stitching/testutil/TestUtil.java +++ b/src/aat/java/uk/gov/hmcts/reform/em/stitching/testutil/TestUtil.java @@ -567,6 +567,10 @@ public static int getOutlinePage(PDOutlineItem outlineItem) throws IOException { return dest == null ? -1 : Math.max(dest.retrievePageNumber(), 0) + 1; } + public String getS2sAuth() { + return s2sAuth; + } + public String getTestUrl() { return testUrl; } From 2895cdde112667ffb9402ff57a88ffce17031fb6 Mon Sep 17 00:00:00 2001 From: mdayican Date: Tue, 24 Mar 2026 15:17:02 +0000 Subject: [PATCH 4/6] EM-7014 fix missing object-level-authorization --- .../DocumentTaskAuthorizationScenarios.java | 42 +++++++++ .../repository/DocumentTaskRepository.java | 4 + .../service/impl/DocumentTaskServiceImpl.java | 13 ++- .../impl/DocumentTaskServiceImplTest.java | 91 +++++++++++++++++++ 4 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DocumentTaskServiceImplTest.java diff --git a/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java b/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java index a004c8c01..f8dd9b4d9 100644 --- a/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java +++ b/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java @@ -52,6 +52,48 @@ void setupNonCaseworkerUser() { .header(SERVICE_AUTH_HEADER, testUtil.getS2sAuth()); } + @Test + void shouldReturnNotFoundWhenDifferentUserAttemptsToGetAnotherUsersTask() throws IOException { + BundleDTO bundle = testUtil.getTestBundle(); + DocumentTaskDTO documentTask = new DocumentTaskDTO(); + documentTask.setBundle(bundle); + + Response createTaskResponse = testUtil.authRequest() + .body(convertObjectToJsonBytes(documentTask)) + .post(DOCUMENT_TASKS_ENDPOINT); + + assertEquals(201, createTaskResponse.getStatusCode(), + "Primary user should be able to create a task."); + String taskId = createTaskResponse.getBody().jsonPath().getString("id"); + + Response getTaskResponse = nonCaseworkerRequest + .get(DOCUMENT_TASKS_ENDPOINT + "/" + taskId); + + assertEquals(404, getTaskResponse.getStatusCode(), + "A different authenticated user must not be able to retrieve another user's task (IDOR)."); + } + + @Test + void shouldReturnTaskWhenOwnerRequestsTheirOwnTask() throws IOException { + BundleDTO bundle = testUtil.getTestBundle(); + DocumentTaskDTO documentTask = new DocumentTaskDTO(); + documentTask.setBundle(bundle); + + Response createTaskResponse = testUtil.authRequest() + .body(convertObjectToJsonBytes(documentTask)) + .post(DOCUMENT_TASKS_ENDPOINT); + + assertEquals(201, createTaskResponse.getStatusCode(), + "Primary user should be able to create a task."); + String taskId = createTaskResponse.getBody().jsonPath().getString("id"); + + Response getTaskResponse = testUtil.authRequest() + .get(DOCUMENT_TASKS_ENDPOINT + "/" + taskId); + + assertEquals(200, getTaskResponse.getStatusCode(), + "The task owner must be able to retrieve their own task."); + } + @Test void shouldFailTaskWhenUserHasNoCaseworkerRole() throws IOException, InterruptedException { BundleDTO bundle = testUtil.getTestBundle(); diff --git a/src/main/java/uk/gov/hmcts/reform/em/stitching/repository/DocumentTaskRepository.java b/src/main/java/uk/gov/hmcts/reform/em/stitching/repository/DocumentTaskRepository.java index ad7895945..7647900be 100644 --- a/src/main/java/uk/gov/hmcts/reform/em/stitching/repository/DocumentTaskRepository.java +++ b/src/main/java/uk/gov/hmcts/reform/em/stitching/repository/DocumentTaskRepository.java @@ -8,10 +8,14 @@ import java.time.Instant; import java.util.List; +import java.util.Optional; @Repository public interface DocumentTaskRepository extends JpaRepository { + Optional findByIdAndCreatedBy(Long id, String createdBy); + + @Query(value = "SELECT m.id FROM versioned_document_task m WHERE m.created_date <= :createdDate limit :numberOfRecords", nativeQuery = true) diff --git a/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DocumentTaskServiceImpl.java b/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DocumentTaskServiceImpl.java index 7f34681a2..263e179c1 100644 --- a/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DocumentTaskServiceImpl.java +++ b/src/main/java/uk/gov/hmcts/reform/em/stitching/service/impl/DocumentTaskServiceImpl.java @@ -2,8 +2,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import uk.gov.hmcts.reform.em.stitching.config.security.SecurityUtils; import uk.gov.hmcts.reform.em.stitching.domain.DocumentTask; import uk.gov.hmcts.reform.em.stitching.info.BuildInfo; import uk.gov.hmcts.reform.em.stitching.repository.DocumentTaskRepository; @@ -19,17 +21,22 @@ @Service public class DocumentTaskServiceImpl implements DocumentTaskService { + public static final String USER_NOT_FOUND = "User not found."; + private final Logger log = LoggerFactory.getLogger(DocumentTaskServiceImpl.class); private final DocumentTaskRepository documentTaskRepository; private final DocumentTaskMapper documentTaskMapper; private final BuildInfo buildInfo; + private final SecurityUtils securityUtils; public DocumentTaskServiceImpl(DocumentTaskRepository documentTaskRepository, DocumentTaskMapper documentTaskMapper, - BuildInfo buildInfo) { + BuildInfo buildInfo, + SecurityUtils securityUtils) { this.documentTaskRepository = documentTaskRepository; this.documentTaskMapper = documentTaskMapper; this.buildInfo = buildInfo; + this.securityUtils = securityUtils; } /** @@ -61,7 +68,9 @@ public DocumentTaskDTO save(DocumentTaskDTO documentTaskDto) { @Transactional(readOnly = true) public Optional findOne(Long id) { log.debug("Request to get DocumentTask : {}", id); - return documentTaskRepository.findById(id) + String currentUser = securityUtils.getCurrentUserLogin() + .orElseThrow(() -> new UsernameNotFoundException(USER_NOT_FOUND)); + return documentTaskRepository.findByIdAndCreatedBy(id, currentUser) .map(documentTaskMapper::toDto); } diff --git a/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DocumentTaskServiceImplTest.java b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DocumentTaskServiceImplTest.java new file mode 100644 index 000000000..b3de3889e --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/em/stitching/service/impl/DocumentTaskServiceImplTest.java @@ -0,0 +1,91 @@ +package uk.gov.hmcts.reform.em.stitching.service.impl; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import uk.gov.hmcts.reform.em.stitching.config.security.SecurityUtils; +import uk.gov.hmcts.reform.em.stitching.domain.DocumentTask; +import uk.gov.hmcts.reform.em.stitching.info.BuildInfo; +import uk.gov.hmcts.reform.em.stitching.repository.DocumentTaskRepository; +import uk.gov.hmcts.reform.em.stitching.service.dto.DocumentTaskDTO; +import uk.gov.hmcts.reform.em.stitching.service.mapper.DocumentTaskMapper; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class DocumentTaskServiceImplTest { + + @Mock + private DocumentTaskRepository documentTaskRepository; + + @Mock + private DocumentTaskMapper documentTaskMapper; + + @Mock + private BuildInfo buildInfo; + + @Mock + private SecurityUtils securityUtils; + + @InjectMocks + private DocumentTaskServiceImpl documentTaskService; + + private static final Long TASK_ID = 1L; + private static final String OWNER = "user-abc"; + private static final String OTHER_USER = "user-xyz"; + + @Test + void findOneReturnsTaskWhenOwnedByCurrentUser() { + DocumentTask task = new DocumentTask(); + DocumentTaskDTO taskDTO = new DocumentTaskDTO(); + when(securityUtils.getCurrentUserLogin()).thenReturn(Optional.of(OWNER)); + when(documentTaskRepository.findByIdAndCreatedBy(TASK_ID, OWNER)).thenReturn(Optional.of(task)); + when(documentTaskMapper.toDto(task)).thenReturn(taskDTO); + + Optional result = documentTaskService.findOne(TASK_ID); + + assertTrue(result.isPresent()); + assertEquals(taskDTO, result.get()); + verify(documentTaskRepository).findByIdAndCreatedBy(TASK_ID, OWNER); + } + + @Test + void findOneReturnsEmptyWhenTaskBelongsToDifferentUser() { + when(securityUtils.getCurrentUserLogin()).thenReturn(Optional.of(OTHER_USER)); + when(documentTaskRepository.findByIdAndCreatedBy(TASK_ID, OTHER_USER)).thenReturn(Optional.empty()); + + Optional result = documentTaskService.findOne(TASK_ID); + + assertTrue(result.isEmpty()); + verify(documentTaskRepository).findByIdAndCreatedBy(TASK_ID, OTHER_USER); + } + + @Test + void findOneThrowsWhenNoAuthenticatedUser() { + when(securityUtils.getCurrentUserLogin()).thenReturn(Optional.empty()); + + assertThrows(UsernameNotFoundException.class, () -> documentTaskService.findOne(TASK_ID)); + + verify(documentTaskRepository, never()).findByIdAndCreatedBy(TASK_ID, null); + } + + @Test + void findOneReturnsEmptyWhenTaskDoesNotExist() { + when(securityUtils.getCurrentUserLogin()).thenReturn(Optional.of(OWNER)); + when(documentTaskRepository.findByIdAndCreatedBy(TASK_ID, OWNER)).thenReturn(Optional.empty()); + + Optional result = documentTaskService.findOne(TASK_ID); + + assertTrue(result.isEmpty()); + } +} From 5c3b220e931aa816b43dfd4953fc569f915301c8 Mon Sep 17 00:00:00 2001 From: mdayican Date: Tue, 24 Mar 2026 16:28:17 +0000 Subject: [PATCH 5/6] fix test --- .../em/stitching/rest/DocumentTaskResourceIntTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/rest/DocumentTaskResourceIntTest.java b/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/rest/DocumentTaskResourceIntTest.java index 2d5b65bf4..edde7f951 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/rest/DocumentTaskResourceIntTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/em/stitching/rest/DocumentTaskResourceIntTest.java @@ -18,6 +18,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import uk.gov.hmcts.reform.authorisation.generators.AuthTokenGenerator; import uk.gov.hmcts.reform.em.stitching.Application; +import uk.gov.hmcts.reform.em.stitching.config.security.SecurityUtils; import uk.gov.hmcts.reform.em.stitching.domain.Bundle; import uk.gov.hmcts.reform.em.stitching.domain.BundleTest; import uk.gov.hmcts.reform.em.stitching.domain.DocumentTask; @@ -32,6 +33,7 @@ import java.io.IOException; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -73,6 +75,9 @@ class DocumentTaskResourceIntTest { @Autowired private OkHttpClient okHttpClient; + @MockitoBean + private SecurityUtils securityUtils; + @MockitoBean private AuthTokenGenerator authTokenGenerator; @@ -112,6 +117,7 @@ void initTest() { defaultTestDocumentTask = createEntity(); MockInterceptor mockInterceptor = (MockInterceptor)okHttpClient.interceptors().get(0); mockInterceptor.reset(); + BDDMockito.given(securityUtils.getCurrentUserLogin()).willReturn(Optional.of("test-user")); } @Test @@ -193,6 +199,7 @@ void createDocumentTaskWithExistingId() throws Exception { @Test void getDocumentTask() throws Exception { // Initialize the database + defaultTestDocumentTask.setCreatedBy("test-user"); documentTaskRepository.saveAndFlush(defaultTestDocumentTask); // Get the documentTask From 210e4c0a7d97343c518004dd253ba7d0c7561b66 Mon Sep 17 00:00:00 2001 From: mdayican Date: Wed, 25 Mar 2026 07:49:15 +0000 Subject: [PATCH 6/6] fix test auth --- .../DocumentTaskAuthorizationScenarios.java | 2 +- .../hmcts/reform/em/stitching/testutil/TestUtil.java | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java b/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java index f8dd9b4d9..c57ac615c 100644 --- a/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java +++ b/src/aat/java/uk/gov/hmcts/reform/em/stitching/functional/DocumentTaskAuthorizationScenarios.java @@ -111,7 +111,7 @@ void shouldFailTaskWhenUserHasNoCaseworkerRole() throws IOException, Interrupted String taskUrl = DOCUMENT_TASKS_ENDPOINT + "/" + createTaskResponse.getBody().jsonPath().getString("id"); - Response taskResponse = testUtil.pollUntil(taskUrl, body -> { + Response taskResponse = testUtil.pollUntil(taskUrl, nonCaseworkerRequest, body -> { String state = body.getString(TASK_STATE_FIELD); return "FAILED".equals(state) || "DONE".equals(state); }); diff --git a/src/aat/java/uk/gov/hmcts/reform/em/stitching/testutil/TestUtil.java b/src/aat/java/uk/gov/hmcts/reform/em/stitching/testutil/TestUtil.java index 1d15eb682..66b1a8242 100644 --- a/src/aat/java/uk/gov/hmcts/reform/em/stitching/testutil/TestUtil.java +++ b/src/aat/java/uk/gov/hmcts/reform/em/stitching/testutil/TestUtil.java @@ -379,15 +379,23 @@ private BundleDocumentDTO getTestBundleDocumentWithSortIndices(String documentUr public Response pollUntil(String endpoint, Predicate evaluator) throws InterruptedException, IOException { - return pollUntil(endpoint, evaluator, 30); + return pollUntil(endpoint, authRequest(), evaluator, 30); + } + + public Response pollUntil(String endpoint, + RequestSpecification requestSpec, + Predicate evaluator) + throws InterruptedException, IOException { + return pollUntil(endpoint, requestSpec, evaluator, 30); } private Response pollUntil(String endpoint, + RequestSpecification requestSpec, Predicate evaluator, int numRetries) throws InterruptedException, IOException { for (int i = 0; i < numRetries; i++) { - Response response = authRequest().get(endpoint); + Response response = requestSpec.get(endpoint); if (response.getStatusCode() == 500) { throw new IOException("HTTP 500 from service");