diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditEvent.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditEvent.kt deleted file mode 100644 index f3aab530..00000000 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditEvent.kt +++ /dev/null @@ -1,20 +0,0 @@ -package uk.gov.justice.digital.hmpps.learnerrecordsapi.config - -import uk.gov.justice.hmpps.sqs.audit.HmppsAuditEvent -import java.time.Instant -import java.util.UUID - -object AuditEvent { - - fun createAuditEvent(whatEvent: String, userName: String, requestParams: String): HmppsAuditEvent { - val hmppsLRSEvent = HmppsAuditEvent( - what = whatEvent, - correlationId = UUID.randomUUID().toString(), - `when` = Instant.now(), - who = userName, - service = "hmpps-learner-records-api", - details = requestParams, - ) - return hmppsLRSEvent - } -} diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditHelper.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditHelper.kt new file mode 100644 index 00000000..308c7f77 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditHelper.kt @@ -0,0 +1,43 @@ +package uk.gov.justice.digital.hmpps.learnerrecordsapi.config + +import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.AuditEvent.MATCH_LE +import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.AuditEvent.MATCH_ULN +import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.AuditEvent.createAuditEvent +import uk.gov.justice.hmpps.sqs.audit.HmppsAuditEvent +import uk.gov.justice.hmpps.sqs.audit.HmppsAuditService +import java.time.Instant +import java.util.UUID + +object AuditEvent { + const val MATCH_ULN = "match-uln" + const val MATCH_LE = "match-learner-events" + + fun createAuditEvent(whatEvent: String, userName: String, requestParams: String): HmppsAuditEvent = HmppsAuditEvent( + what = whatEvent, + correlationId = UUID.randomUUID().toString(), + `when` = Instant.now(), + who = userName, + service = "hmpps-learner-records-api", + details = requestParams, + ) +} + +class AuditHelper(private val auditService: HmppsAuditService) { + + private suspend fun publishAuditEvent(whatEvent: String, userName: String, requestParams: String) { + val hmppsLRSEvent = createAuditEvent( + whatEvent, + userName, + requestParams, + ) + auditService.publishEvent(hmppsLRSEvent) + } + + suspend fun publishMatchAuditEvent(userName: String, nomisId: String) { + publishAuditEvent(MATCH_ULN, userName, nomisId) + } + + suspend fun publishLearnerEventsAuditEvent(userName: String, nomisId: String) { + publishAuditEvent(MATCH_LE, userName, nomisId) + } +} diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/resource/MatchResource.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/resource/MatchResource.kt index 7afa94ae..bef52d1b 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/resource/MatchResource.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/resource/MatchResource.kt @@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController -import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.AuditEvent.createAuditEvent +import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.AuditHelper import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.Roles.ROLE_LEARNERS_RO import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.Roles.ROLE_LEARNERS_UI import uk.gov.justice.digital.hmpps.learnerrecordsapi.logging.LoggerUtil @@ -27,6 +27,7 @@ import uk.gov.justice.digital.hmpps.learnerrecordsapi.openapi.MatchCheckApi import uk.gov.justice.digital.hmpps.learnerrecordsapi.openapi.MatchConfirmApi import uk.gov.justice.digital.hmpps.learnerrecordsapi.service.LearnerEventsService import uk.gov.justice.digital.hmpps.learnerrecordsapi.service.MatchService +import uk.gov.justice.hmpps.kotlin.auth.HmppsAuthenticationHolder import uk.gov.justice.hmpps.sqs.audit.HmppsAuditService import java.net.URI @@ -35,20 +36,25 @@ import java.net.URI class MatchResource( private val matchService: MatchService, private val learnerEventsService: LearnerEventsService, - private val auditService: HmppsAuditService, + auditService: HmppsAuditService, + private val authHolder: HmppsAuthenticationHolder, ) { val logger = LoggerUtil.getLogger() - val searchLearnerEventsByNomisId = "SEARCH_LEARNER_EVENTS_BY_NOMISID" + private val auditHelper = AuditHelper(auditService) @PreAuthorize("hasAnyRole('$ROLE_LEARNERS_UI', '$ROLE_LEARNERS_RO')") @GetMapping("/{nomisId}") @Tag(name = "Match") @MatchCheckApi - fun findMatch( + suspend fun findMatch( @PathVariable(name = "nomisId", required = true) nomisId: String, @RequestHeader("X-Username", required = true) userName: String, ): ResponseEntity { + val roles = authHolder.roles.map { it?.authority ?: "" } + if (roles.contains(ROLE_LEARNERS_RO)) { + auditHelper.publishMatchAuditEvent(userName, nomisId) + } logger.log("Received a get request to match endpoint", nomisId) return matchService.findMatch(nomisId)?.let { ResponseEntity.status(HttpStatus.OK).body( @@ -83,7 +89,7 @@ class MatchResource( @PathVariable(name = "nomisId", required = true) nomisId: String, @RequestHeader("X-Username", required = true) userName: String, ): ResponseEntity { - auditService.publishEvent(createAuditEvent(searchLearnerEventsByNomisId, userName, nomisId)) + auditHelper.publishLearnerEventsAuditEvent(userName, nomisId) logger.log("Received a post request to learner events by Nomis ID endpoint", nomisId) val checkMatchResponse: CheckMatchResponse? = learnerEventsService.getMatchEntityForNomisId(nomisId) if (checkMatchResponse == null) { diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditEventTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditEventTest.kt index 655742bc..ee95388d 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditEventTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/AuditEventTest.kt @@ -4,6 +4,7 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test +import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.AuditEvent.createAuditEvent import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.Gender import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.LearnersRequest import java.time.Instant @@ -20,7 +21,7 @@ class AuditEventTest { lastKnownPostCode = "NE2 2AS", emailAddress = "test@example.com", ) - val hmppsAuditEvent = AuditEvent.createAuditEvent("searchLearnersByDemographics", "User", request.toString()) + val hmppsAuditEvent = createAuditEvent("searchLearnersByDemographics", "User", request.toString()) assertEquals("hmpps-learner-records-api", hmppsAuditEvent.service) assertEquals("searchLearnersByDemographics", hmppsAuditEvent.what) assertEquals("User", hmppsAuditEvent.who) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/MatchResourceIntTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/MatchResourceIntTest.kt index b2840c8e..1a6c462e 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/MatchResourceIntTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/MatchResourceIntTest.kt @@ -20,6 +20,7 @@ import org.springframework.http.MediaType import org.springframework.test.web.reactive.server.WebTestClient import software.amazon.awssdk.services.sqs.model.PurgeQueueRequest import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest +import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.AuditEvent.MATCH_LE import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.HmppsBoldLrsExceptionHandler import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.Roles.ROLE_LEARNERS_RO import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.Roles.ROLE_LEARNERS_UI @@ -266,7 +267,7 @@ class MatchResourceIntTest : IntegrationTestBase() { HmppsAuditEvent::class.java, ) - assertThat(receivedEvent.what).isEqualTo("SEARCH_LEARNER_EVENTS_BY_NOMISID") + assertThat(receivedEvent.what).isEqualTo(MATCH_LE) assertThat(receivedEvent.who).isEqualTo("TestUser") assertThat(receivedEvent.service).isEqualTo("hmpps-learner-records-api") assertThat(receivedEvent.`when`).isBeforeOrEqualTo(Instant.now()) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/resource/MatchResourceTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/resource/MatchResourceTest.kt index 622c76c3..e651d65e 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/resource/MatchResourceTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/resource/MatchResourceTest.kt @@ -10,12 +10,18 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.`when` import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import org.springframework.http.HttpStatus +import org.springframework.security.core.GrantedAuthority +import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.Roles.ROLE_LEARNERS_RO +import uk.gov.justice.digital.hmpps.learnerrecordsapi.config.Roles.ROLE_LEARNERS_UI import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response.exceptions.MatchNotFoundException import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.CheckMatchResponse import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.CheckMatchStatus import uk.gov.justice.digital.hmpps.learnerrecordsapi.service.LearnerEventsService import uk.gov.justice.digital.hmpps.learnerrecordsapi.service.MatchService +import uk.gov.justice.hmpps.kotlin.auth.HmppsAuthenticationHolder import uk.gov.justice.hmpps.sqs.audit.HmppsAuditService import java.time.LocalDate @@ -33,50 +39,60 @@ class MatchResourceTest { private lateinit var learnerEventsResource: LearnerEventsResource private lateinit var mockAuditService: HmppsAuditService private lateinit var mockLearnerEventsService: LearnerEventsService + private lateinit var mockAuthHolder: HmppsAuthenticationHolder @BeforeEach fun setup() { mockMatchService = mock(MatchService::class.java) mockLearnerEventsService = mock(LearnerEventsService::class.java) mockAuditService = mock(HmppsAuditService::class.java) - matchResource = MatchResource(mockMatchService, mockLearnerEventsService, mockAuditService) + mockAuthHolder = mock(HmppsAuthenticationHolder::class.java) + matchResource = MatchResource(mockMatchService, mockLearnerEventsService, mockAuditService, mockAuthHolder) learnerEventsResource = LearnerEventsResource(mockLearnerEventsService) } + private fun setRoleAndUln(role: String, uln: String?) { + `when`(mockAuthHolder.roles).thenReturn( + listOf(GrantedAuthority { role }), + ) + `when`(mockMatchService.findMatch(any())).thenReturn( + uln?.let { + CheckMatchResponse( + matchedUln = it, + ) + }, + ) + } + @Test - fun `should return NOT_FOUND if no record found`() { - `when`(mockMatchService.findMatch(any())).thenReturn(null) + fun `should return NOT_FOUND if no record found`() = runTest { + setRoleAndUln(ROLE_LEARNERS_UI, null) val actual = matchResource.findMatch(nomisId, "") assertThat(actual.statusCode).isEqualTo(HttpStatus.NOT_FOUND) assertThat(actual.body?.status ?: "").isEqualTo(CheckMatchStatus.NotFound) + verify(mockAuditService, times(0)).publishEvent(any()) } @Test - fun `should return entity if record found`() { - `when`(mockMatchService.findMatch(any())).thenReturn( - CheckMatchResponse( - matchedUln = matchedUln, - ), - ) + fun `should return entity if record found`() = runTest { + setRoleAndUln(ROLE_LEARNERS_RO, matchedUln) val actual = matchResource.findMatch(nomisId, "") assertThat(actual.statusCode).isEqualTo(HttpStatus.OK) assertThat(actual.body?.matchedUln ?: "").isEqualTo(matchedUln) assertThat(actual.body?.status ?: "").isEqualTo(CheckMatchStatus.Found) + verify(mockAuditService, times(1)).publishEvent(any()) } @Test - fun `should return NO_MATCH if id cannot be matched`() { - `when`(mockMatchService.findMatch(any())).thenReturn( - CheckMatchResponse( - matchedUln = "", - ), - ) + fun `should return NO_MATCH if id cannot be matched`() = runTest { + setRoleAndUln(ROLE_LEARNERS_UI, "") val actual = matchResource.findMatch(nomisId, "") assertThat(actual.statusCode).isEqualTo(HttpStatus.OK) assertThat(actual.body?.status ?: "").isEqualTo(CheckMatchStatus.NoMatch) + verify(mockAuditService, times(0)).publishEvent(any()) } @Test @@ -86,6 +102,7 @@ class MatchResourceTest { matchResource.findLearnerEventsByNomisId(nomisId, "") } assertThat(exception.message).isEqualTo(nomisId) + verify(mockAuditService, times(1)).publishEvent(any()) } @Test