diff --git a/libs/commons/src/main/kotlin/uk/gov/justice/digital/hmpps/ldap/LdapTemplateExtensions.kt b/libs/commons/src/main/kotlin/uk/gov/justice/digital/hmpps/ldap/LdapTemplateExtensions.kt index 88fe1c648c..bac1d938bf 100644 --- a/libs/commons/src/main/kotlin/uk/gov/justice/digital/hmpps/ldap/LdapTemplateExtensions.kt +++ b/libs/commons/src/main/kotlin/uk/gov/justice/digital/hmpps/ldap/LdapTemplateExtensions.kt @@ -2,6 +2,7 @@ package uk.gov.justice.digital.hmpps.ldap import io.opentelemetry.instrumentation.annotations.SpanAttribute import io.opentelemetry.instrumentation.annotations.WithSpan +import org.springframework.ldap.NameNotFoundException import org.springframework.ldap.core.AttributesMapper import org.springframework.ldap.core.LdapTemplate import org.springframework.ldap.query.LdapQuery @@ -25,26 +26,32 @@ inline fun LdapTemplate.findByUsername(@SpanAttribute username: Stri fun LdapTemplate.findEmailByUsername(@SpanAttribute username: String) = findAttributeByUsername(username, "mail") @WithSpan -fun LdapTemplate.findAttributeByUsername(@SpanAttribute username: String, @SpanAttribute attribute: String) = search( - query() +fun LdapTemplate.findAttributeByUsername(@SpanAttribute username: String, @SpanAttribute attribute: String) = try { + search(query() .attributes(attribute) .searchScope(SearchScope.ONELEVEL) .where("objectclass").`is`("inetOrgPerson") .and("objectclass").`is`("top") .and("cn").`is`(username), - AttributesMapper { it[attribute]?.get()?.toString() } -).singleOrNull() + AttributesMapper { it[attribute]?.get()?.toString() } + ).singleOrNull() +} catch (_: NameNotFoundException) { + throw NotFoundException("NDeliusUser of $username not found") +} @WithSpan -fun LdapTemplate.getRoles(@SpanAttribute username: String) = search( - query() +fun LdapTemplate.getRoles(@SpanAttribute username: String) = try { + search(query() .attributes("cn") .base(LdapNameBuilder.newInstance().add("cn", username).build()) .searchScope(SearchScope.ONELEVEL) .where("objectclass").`is`("NDRole") .or("objectclass").`is`("NDRoleAssociation"), - AttributesMapper { it["cn"]?.get()?.toString() } -).filterNotNull() + AttributesMapper { it["cn"]?.get()?.toString() } + ).filterNotNull() +} catch (_: NameNotFoundException) { + throw NotFoundException("NDeliusUser of $username not found") +} @WithSpan fun LdapTemplate.addRole(@SpanAttribute username: String, @SpanAttribute role: DeliusRole) { @@ -56,12 +63,20 @@ fun LdapTemplate.addRole(@SpanAttribute username: String, @SpanAttribute role: D put(listOf("NDRoleAssociation", "alias", "top").asAttribute("objectclass")) } val userRole = role.context(username) - rebind(userRole, null, attributes) + try { + rebind(userRole, null, attributes) + } catch (_: NameNotFoundException) { + throw NotFoundException("NDeliusUser of $username not found") + } } @WithSpan fun LdapTemplate.removeRole(@SpanAttribute username: String, @SpanAttribute role: DeliusRole) = - unbind(role.context(username)) + try { + unbind(role.context(username)) + } catch (_: NameNotFoundException) { + throw NotFoundException("NDeliusUser of $username not found") + } private fun DeliusRole.context(username: String? = null) = LdapNameBuilder.newInstance() diff --git a/libs/commons/src/test/kotlin/uk/gov/justice/digital/hmpps/ldap/LdapTemplateExtensionsTest.kt b/libs/commons/src/test/kotlin/uk/gov/justice/digital/hmpps/ldap/LdapTemplateExtensionsTest.kt index 89f3be651b..f05ab73e63 100644 --- a/libs/commons/src/test/kotlin/uk/gov/justice/digital/hmpps/ldap/LdapTemplateExtensionsTest.kt +++ b/libs/commons/src/test/kotlin/uk/gov/justice/digital/hmpps/ldap/LdapTemplateExtensionsTest.kt @@ -8,11 +8,13 @@ import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.* +import org.springframework.ldap.NameNotFoundException import org.springframework.ldap.core.AttributesMapper import org.springframework.ldap.core.DirContextOperations import org.springframework.ldap.core.LdapTemplate import uk.gov.justice.digital.hmpps.exception.NotFoundException import uk.gov.justice.digital.hmpps.ldap.entity.LdapUser +import javax.naming.Name import javax.naming.directory.Attributes import javax.naming.ldap.LdapName @@ -116,4 +118,59 @@ class LdapTemplateExtensionsTest { assertThat(it.toString(), equalTo("cn=ROLE1,cn=john-smith")) }) } + + @Test + fun `unknown username throws NotFoundException when getting roles`() { + + whenever(ldapTemplate.search(any(), any>())) + .thenThrow(NameNotFoundException("No Such Object")) + + assertThrows { ldapTemplate.getRoles("test") } + } + + @Test + fun `unknown username throws NotFoundException finding by username`() { + + whenever(ldapTemplate.search(any(), any>())) + .thenThrow(NameNotFoundException("No Such Object")) + + assertThrows { ldapTemplate.findEmailByUsername("test") } + } + + @Test + fun `unknown username throws NotFoundException when adding roles`() { + whenever(ldapTemplate.lookupContext(any())) + .thenReturn(dirContextOperations) + whenever(dirContextOperations.nameInNamespace) + .thenReturn("cn=ROLE1,cn=ndRoleCatalogue,ou=Users,dc=moj,dc=com") + + whenever(ldapTemplate.rebind(any(), anyOrNull(), any())).thenThrow( + NameNotFoundException("No Such Object") + ) + whenever(ldapTemplate.unbind(any())).thenThrow( + NameNotFoundException("No Such Object") + ) + + assertThrows { + ldapTemplate.addRole( + "test", + object : DeliusRole { + override val description = "Role One Description" + override val mappedRole = "MAPPED_ROLE_ONE" + override val name = "ROLE1" + } + ) + } + + assertThrows { + ldapTemplate.removeRole( + "test", + object : DeliusRole { + override val description = "Role One Description" + override val mappedRole = "MAPPED_ROLE_ONE" + override val name = "ROLE1" + } + ) + } + } } diff --git a/projects/hdc-licences-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserIntegrationTest.kt b/projects/hdc-licences-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserIntegrationTest.kt index 621c41aa4c..3b56ad53b9 100644 --- a/projects/hdc-licences-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserIntegrationTest.kt +++ b/projects/hdc-licences-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserIntegrationTest.kt @@ -59,4 +59,16 @@ internal class UserIntegrationTest { mockMvc.perform(delete("/users/test.user/roles/LHDCBT003").withToken()) .andExpect(status().isOk) } + + @Test + fun `non existent user returns not found`() { + mockMvc.perform(put("/users/nonexistent.user/roles/LHDCBT003").withToken()) + .andExpect(status().isNotFound) + mockMvc + .perform(delete("/users/nonexistent.user/roles/LHDCBT003").withToken()) + .andExpect(status().isNotFound) + mockMvc + .perform(get("/users/nonexistent.user/details").withToken()) + .andExpect(status().isNotFound) + } }