Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.mosip.idrepository.core.exception.IdRepoDataValidationException;
import io.mosip.idrepository.core.exception.IdRepoExceptionHandler;
import io.mosip.idrepository.core.logger.IdRepoLogger;
import io.mosip.idrepository.core.repository.UinHashSaltRepo;
import io.mosip.idrepository.core.security.IdRepoSecurityManager;
import io.mosip.kernel.core.exception.ExceptionUtils;
import io.mosip.kernel.core.http.RequestWrapper;
Expand Down Expand Up @@ -51,6 +52,25 @@ public class AuditHelper {
@Autowired
private IdRepoSecurityManager securityManager;

// Credential services do not provide this repository. Omit the subject if it
// is unavailable so audit records never contain an unsalted identifier.
@Autowired(required = false)
private UinHashSaltRepo uinHashSaltRepo;

private String hashAuditId(String id) {
if (uinHashSaltRepo == null) {
return null;
}
try {
return securityManager.getIdHashWithSaltModuloByPlainIdHash(
id, uinHashSaltRepo::retrieveSaltById);
} catch (Exception e) {
mosipLogger.error(IdRepoSecurityManager.getUser(), "AuditHelper", "hashAuditId",
"Unable to hash audit subject with salt");
return null;
}
}

/** The mapper. */
@Autowired
private ObjectMapper mapper;
Expand All @@ -67,7 +87,7 @@ public class AuditHelper {
public void audit(AuditModules module, AuditEvents event, String id, IdType idType, String desc) {
String requestId = null;
if(id !=null) {
requestId = securityManager.hash(id.getBytes());
requestId = hashAuditId(id);
}
RequestWrapper<AuditRequestDTO> auditRequest = auditBuilder.buildRequest(module, event,
requestId, idType, desc);
Expand All @@ -89,7 +109,7 @@ public void audit(AuditModules module, AuditEvents event, String id, IdType idTy
* Audit - asynchronously calls audit service (fire-and-forget).
*/
public void auditAsync(AuditModules module, AuditEvents event, String id, IdType idType, String desc) {
String requestId = (id != null) ? securityManager.hash(id.getBytes()) : null;
String requestId = (id != null) ? hashAuditId(id) : null;

RequestWrapper<AuditRequestDTO> auditRequest = auditBuilder.buildRequest(
module, event, requestId, idType, desc);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package io.mosip.idrepository.core.test.helper;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.concurrent.CompletableFuture;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
Expand Down Expand Up @@ -33,8 +40,12 @@
import io.mosip.idrepository.core.exception.IdRepoDataValidationException;
import io.mosip.idrepository.core.helper.AuditHelper;
import io.mosip.idrepository.core.helper.RestHelper;
import io.mosip.idrepository.core.dto.AuditRequestDTO;
import io.mosip.idrepository.core.dto.RestRequestDTO;
import io.mosip.idrepository.core.repository.UinHashSaltRepo;
import io.mosip.idrepository.core.security.IdRepoSecurityManager;
import io.mosip.idrepository.core.util.EnvUtil;
import io.mosip.kernel.core.http.RequestWrapper;

/**
* @author Manoj SP
Expand All @@ -54,6 +65,9 @@ public class AuditHelperTest {
@Mock
IdRepoSecurityManager securityManager;

@Mock
UinHashSaltRepo uinHashSaltRepo;

@Autowired
MockMvc mockMvc;

Expand All @@ -70,7 +84,71 @@ public class AuditHelperTest {
public void before() {
ReflectionTestUtils.setField(restBuilder, "env", env);
ReflectionTestUtils.setField(auditHelper, "mapper", new ObjectMapper());
when(securityManager.hash(Mockito.any())).thenReturn("mock");
when(securityManager.getIdHashWithSaltModuloByPlainIdHash(
Mockito.anyString(), Mockito.any())).thenReturn("salted-hash");
}

@Test
public void testAuditAndAuditAsyncUseSaltedHash() throws IdRepoDataValidationException {
String uin = "1234567890";
when(restBuilder.buildRequest(Mockito.any(), Mockito.any(), Mockito.any()))
.thenReturn(mock(RestRequestDTO.class));
when(restHelper.requestAsync(Mockito.any()))
.thenReturn(CompletableFuture.completedFuture(null));

auditHelper.audit(AuditModules.ID_REPO_CORE_SERVICE,
AuditEvents.CREATE_IDENTITY_REQUEST_RESPONSE, uin, IdType.UIN, "desc");
auditHelper.auditAsync(AuditModules.ID_REPO_CORE_SERVICE,
AuditEvents.CREATE_IDENTITY_REQUEST_RESPONSE, uin, IdType.UIN, "desc");

ArgumentCaptor<String> idCaptor = ArgumentCaptor.forClass(String.class);
verify(auditBuilder, Mockito.times(2)).buildRequest(
Mockito.any(), Mockito.any(), idCaptor.capture(), Mockito.any(), Mockito.any());
assertEquals(Arrays.asList("salted-hash", "salted-hash"), idCaptor.getAllValues());
verify(securityManager, Mockito.times(2))
.getIdHashWithSaltModuloByPlainIdHash(Mockito.eq(uin), Mockito.any());
verify(securityManager, never()).hash(Mockito.any());
}

@Test
public void testAuditOmitsSubjectWhenRepoAbsent() throws Exception {
ReflectionTestUtils.setField(auditHelper, "uinHashSaltRepo", null);
RequestWrapper<AuditRequestDTO> auditRequest = new RequestWrapper<>();
RestRequestDTO restRequest = mock(RestRequestDTO.class);
when(auditBuilder.buildRequest(Mockito.any(), Mockito.any(), Mockito.isNull(),
Mockito.any(), Mockito.any())).thenReturn(auditRequest);
when(restBuilder.buildRequest(Mockito.any(), Mockito.eq(auditRequest), Mockito.any()))
.thenReturn(restRequest);

auditHelper.audit(AuditModules.ID_REPO_CORE_SERVICE,
AuditEvents.CREATE_IDENTITY_REQUEST_RESPONSE, "1234567890", IdType.UIN, "desc");

verify(auditBuilder).buildRequest(Mockito.any(), Mockito.any(), Mockito.isNull(),
Mockito.any(), Mockito.any());
verify(restHelper).requestSync(restRequest);
verify(securityManager, never()).getIdHashWithSaltModuloByPlainIdHash(Mockito.any(), Mockito.any());
verify(securityManager, never()).hash(Mockito.any());
}

@Test
public void testAuditAsyncOmitsSubjectWhenSaltedHashThrows() throws IdRepoDataValidationException {
when(securityManager.getIdHashWithSaltModuloByPlainIdHash(Mockito.anyString(), Mockito.any()))
.thenThrow(new RuntimeException("db down"));
RequestWrapper<AuditRequestDTO> auditRequest = new RequestWrapper<>();
RestRequestDTO restRequest = mock(RestRequestDTO.class);
when(auditBuilder.buildRequest(Mockito.any(), Mockito.any(), Mockito.isNull(),
Mockito.any(), Mockito.any())).thenReturn(auditRequest);
when(restBuilder.buildRequest(Mockito.any(), Mockito.eq(auditRequest), Mockito.any()))
.thenReturn(restRequest);
when(restHelper.requestAsync(restRequest)).thenReturn(CompletableFuture.completedFuture(null));

auditHelper.auditAsync(AuditModules.ID_REPO_CORE_SERVICE,
AuditEvents.CREATE_IDENTITY_REQUEST_RESPONSE, "1234567890", IdType.UIN, "desc");

verify(auditBuilder).buildRequest(Mockito.any(), Mockito.any(), Mockito.isNull(),
Mockito.any(), Mockito.any());
verify(restHelper).requestAsync(restRequest);
verify(securityManager, never()).hash(Mockito.any());
}

@Test
Expand Down
Loading