From 6c81afcd526ae031d521cae8cf944ee8321af714 Mon Sep 17 00:00:00 2001 From: RIHTARSIC Joze <joze.rihtarsic@ext.ec.europa.eu> Date: Thu, 22 Jun 2023 11:55:24 +0200 Subject: [PATCH] add unit tests --- .../smp/conversion/IdentifierService.java | 12 +- .../edelivery/smp/data/dao/TestUtilsDao.java | 30 ++- .../AbstractServiceIntegrationTest.java | 6 + .../smp/services/CredentialServiceTest.java | 189 ++++++++++++++++-- .../edelivery/smp/testutil/TestConstants.java | 3 + 5 files changed, 219 insertions(+), 21 deletions(-) diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/IdentifierService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/IdentifierService.java index 01491d5f7..d412bdefb 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/IdentifierService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/IdentifierService.java @@ -16,7 +16,6 @@ package eu.europa.ec.edelivery.smp.conversion; import eu.europa.ec.edelivery.smp.identifiers.Identifier; import eu.europa.ec.edelivery.smp.identifiers.IdentifierFormatter; import eu.europa.ec.edelivery.smp.identifiers.types.EBCorePartyIdFormatterType; -import eu.europa.ec.edelivery.smp.identifiers.types.OasisSMPFormatterType; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.ConfigurationService; @@ -51,8 +50,8 @@ public class IdentifierService { /** * Update ParticipantIdentifierFormatter for non null values. Null values are ignored * - * @param caseInsensitiveSchemas - * @param mandatoryScheme + * @param caseInsensitiveSchemas list of schemas for which case insensitivity is required + * @param mandatoryScheme if true, scheme is mandatory */ public void configureParticipantIdentifierFormatter(List<String> caseInsensitiveSchemas, Boolean mandatoryScheme, Pattern allowedSchemeRegExp) { if (caseInsensitiveSchemas != null) { @@ -62,7 +61,7 @@ public class IdentifierService { } if (mandatoryScheme != null) { - participantIdentifierFormatter.setSchemeMandatory(mandatoryScheme.booleanValue()); + participantIdentifierFormatter.setSchemeMandatory(mandatoryScheme); } else { LOG.debug("Skip configure ParticipantIdentifierFormatter.mandatoryScheme for null value"); } @@ -74,6 +73,11 @@ public class IdentifierService { } } + /** + * Update DocumentIdentifierFormatter for non null values. Null values are ignored + * + * @param caseInsensitiveSchemas list of schemas for which case insensitivity is required + */ public void configureDocumentIdentifierFormatter(List<String> caseInsensitiveSchemas) { if (caseInsensitiveSchemas != null) { documentIdentifierFormatter.setCaseSensitiveSchemas(caseInsensitiveSchemas); diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/TestUtilsDao.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/TestUtilsDao.java index 7045423cd..5a386e165 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/TestUtilsDao.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/TestUtilsDao.java @@ -11,13 +11,12 @@ import eu.europa.ec.edelivery.smp.data.model.doc.DBSubresource; import eu.europa.ec.edelivery.smp.data.model.ext.DBExtension; import eu.europa.ec.edelivery.smp.data.model.ext.DBResourceDef; import eu.europa.ec.edelivery.smp.data.model.ext.DBSubresourceDef; -import eu.europa.ec.edelivery.smp.data.model.user.DBDomainMember; -import eu.europa.ec.edelivery.smp.data.model.user.DBGroupMember; -import eu.europa.ec.edelivery.smp.data.model.user.DBResourceMember; -import eu.europa.ec.edelivery.smp.data.model.user.DBUser; +import eu.europa.ec.edelivery.smp.data.model.user.*; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.testutil.TestDBUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCrypt; import org.springframework.stereotype.Repository; import javax.persistence.EntityManager; @@ -37,6 +36,9 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; */ @Repository public class TestUtilsDao { + + @Autowired + UserDao userDao; @PersistenceContext protected EntityManager memEManager; private static final SMPLogger LOG = SMPLoggerFactory.getLogger(TestUtilsDao.class); @@ -211,8 +213,16 @@ public class TestUtilsDao { return; } user1 = createDBUserByUsername(USERNAME_1); + DBCredential c1 = TestDBUtils.createDBCredentialForUser(user1, null, null, null); + c1.setValue(BCrypt.hashpw(USERNAME_1_PASSWORD, BCrypt.gensalt())); + user1.getUserCredentials().add(c1); user2 = createDBUserByCertificate(USER_CERT_2); user3 = createDBUserByUsername(USERNAME_3); + DBCredential c3 = TestDBUtils.createDBCredentialForUserAccessToken(user3, null, null, null); + c3.setValue(BCrypt.hashpw(USERNAME_3_AT_PASSWORD, BCrypt.gensalt())); + c3.setName(USERNAME_3_AT); + user3.getUserCredentials().add(c3); + user4 = createDBUserByUsername(USERNAME_4); user5 = createDBUserByUsername(USERNAME_5); @@ -229,6 +239,18 @@ public class TestUtilsDao { assertNotNull(user5.getId()); } + @Transactional + public void deactivateUser(String username) { + DBUser user = userDao.findUserByUsername(username).get(); + user.setActive(false); + persistFlushDetach(user); + } + + @Transactional + public void updateCredentials(DBCredential credential) { + merge(credential); + } + /** * Create domain members for * user1 on domain 1 as Admin diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceIntegrationTest.java index 595a631a6..708cc7f03 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceIntegrationTest.java @@ -10,6 +10,7 @@ import eu.europa.ec.edelivery.smp.data.dao.*; import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.data.model.doc.DBResource; import eu.europa.ec.edelivery.smp.data.model.doc.DBSubresource; +import eu.europa.ec.edelivery.smp.data.model.user.DBCredential; import eu.europa.ec.edelivery.smp.data.model.user.DBUser; import eu.europa.ec.edelivery.smp.services.mail.MailService; import eu.europa.ec.edelivery.smp.services.spi.SmpXmlSignatureService; @@ -23,6 +24,7 @@ import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCrypt; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -83,6 +85,7 @@ public abstract class AbstractServiceIntegrationTest extends AbstractBaseDao { @Autowired DBAssertion dbAssertion; + @Before public void before() throws IOException { resetKeystore(); @@ -113,11 +116,14 @@ public abstract class AbstractServiceIntegrationTest extends AbstractBaseDao { domainDao.persistFlushDetach(testDomain01); DBUser u1 = TestDBUtils.createDBUserByUsername(TestConstants.USERNAME_1); + DBCredential c1 = TestDBUtils.createDBCredentialForUser(u1, null, null, null); + c1.setValue(BCrypt.hashpw(USERNAME_1_PASSWORD, BCrypt.gensalt())); DBUser u2 = TestDBUtils.createDBUserByCertificate(TestConstants.USER_CERT_2); DBUser u3 = TestDBUtils.createDBUserByUsername(TestConstants.USERNAME_2); userDao.persistFlushDetach(u1); userDao.persistFlushDetach(u2); userDao.persistFlushDetach(u3); + credentialDao.persistFlushDetach(c1); DBResource sg1d1 = TestDBUtils.createDBResource(TEST_SG_ID_1, TEST_SG_SCHEMA_1); DBSubresource sg1md1 = TestDBUtils.createDBSubresource(TEST_SG_ID_1, TEST_SG_SCHEMA_1, diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/CredentialServiceTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/CredentialServiceTest.java index 84f633558..360a910a9 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/CredentialServiceTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/CredentialServiceTest.java @@ -1,59 +1,222 @@ package eu.europa.ec.edelivery.smp.services; + +import eu.europa.ec.edelivery.smp.data.model.user.DBCredential; +import eu.europa.ec.edelivery.smp.testutil.TestConstants; +import org.hamcrest.MatcherAssert; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.test.context.junit4.SpringRunner; + +import java.time.OffsetDateTime; import static org.junit.Assert.*; -public class CredentialServiceTest { +@RunWith(SpringRunner.class) +public class CredentialServiceTest extends AbstractServiceIntegrationTest { + @Autowired + CredentialService testInstance; + @Before + public void beforeMethods() { + testUtilsDao.clearData(); + testUtilsDao.createUsers(); + } + @Test - public void authenticateByUsernamePassword() { + public void authenticateByUsernamePasswordTestBadUsername() { + // given + String username = "usernameNotExists"; + String password = "password"; + // when + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByUsernamePassword(username, password)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("Login failed; Invalid userID or password!")); } @Test - public void authenticateByAuthenticationToken() { + public void authenticateByUsernamePasswordTestOk() { + // given + String username = TestConstants.USERNAME_1; + String password = TestConstants.USERNAME_1_PASSWORD; + // when + Authentication authentication = testInstance.authenticateByUsernamePassword(username, password); + // then + assertEquals(username, authentication.getName()); + assertTrue(authentication.isAuthenticated()); + assertEquals(1, authentication.getAuthorities().size()); + assertEquals("ROLE_USER", authentication.getAuthorities().iterator().next().getAuthority()); } @Test - public void isNotValidCredential() { + public void authenticateByUsernamePasswordTestBadPassword() { + // given + String username = TestConstants.USERNAME_1; + String password = "password"; + // when + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByUsernamePassword(username, password)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("Login failed; Invalid userID or password!")); } @Test - public void authenticateByCertificateToken() { + public void authenticateByUsernamePasswordInactive() { + testUtilsDao.deactivateUser(TestConstants.USERNAME_1); + + // given + String username = TestConstants.USERNAME_1; + String password = TestConstants.USERNAME_1_PASSWORD; + // when then + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByUsernamePassword(username, password)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("Login failed; Invalid userID or password!")); } @Test - public void validateCertificatePolicyMatchLegacy() { + public void authenticateByUsernameCredentialsInactive() { + DBCredential credential = testUtilsDao.getUser1().getUserCredentials().get(0); + credential.setActive(false); + testUtilsDao.updateCredentials(credential); + + // given + String username = TestConstants.USERNAME_1; + String password = TestConstants.USERNAME_1_PASSWORD; + // when then + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByUsernamePassword(username, password)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("Login failed; Invalid userID or password!")); } @Test - public void delayResponse() { + public void authenticateByUsernameCredentialsSuspended() { + DBCredential credential = testUtilsDao.getUser1().getUserCredentials().get(0); + credential.setLastFailedLoginAttempt(OffsetDateTime.now()); + credential.setSequentialLoginFailureCount(100); + testUtilsDao.updateCredentials(credential); + + // given + String username = TestConstants.USERNAME_1; + String password = TestConstants.USERNAME_1_PASSWORD; + // when then + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByUsernamePassword(username, password)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("The user credential is suspended. Please try again later or contact your administrator.")); } @Test - public void loginAttemptFailedAndThrowError() { + public void authenticateByUsernameCredentialsNotSuspendedAnymore() { + DBCredential credential = testUtilsDao.getUser1().getUserCredentials().get(0); + credential.setLastFailedLoginAttempt(OffsetDateTime.now().minusDays(100)); + credential.setSequentialLoginFailureCount(100); + testUtilsDao.updateCredentials(credential); + + // given + String username = TestConstants.USERNAME_1; + String password = TestConstants.USERNAME_1_PASSWORD; + // when then + Authentication authentication = testInstance.authenticateByUsernamePassword(username, password); + // then + assertEquals(username, authentication.getName()); } + + @Test - public void validateIfCredentialIsSuspended() { + public void authenticateByAccessTokenBadUsername() { + // given + String accessTokenName = "usernameNotExists"; + String accessTokenValue = "password"; + // when + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByAuthenticationToken(accessTokenName, accessTokenValue)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("Login failed; Invalid userID or password!")); } @Test - public void getLoginMaxAttempts() { + public void authenticateByAccessTokenTestOk() { + // given + String accessTokenName = TestConstants.USERNAME_3_AT; + String accessTokenValue = TestConstants.USERNAME_3_AT_PASSWORD; + // when + Authentication authentication = testInstance.authenticateByAuthenticationToken(accessTokenName, accessTokenValue); + // then + assertEquals(TestConstants.USERNAME_3_AT, authentication.getName()); + assertTrue(authentication.isAuthenticated()); + assertEquals(1, authentication.getAuthorities().size()); + assertEquals("ROLE_WS_USER", authentication.getAuthorities().iterator().next().getAuthority()); } @Test - public void getLoginSuspensionTimeInSeconds() { + public void authenticateByAccessTokenBadPassword() { + // given + String accessTokenName = TestConstants.USERNAME_3_AT; + String accessTokenValue = "badPassword"; + + // when + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByAuthenticationToken(accessTokenName, accessTokenValue)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("Login failed; Invalid userID or password!")); } @Test - public void getAlertBeforeUserSuspendedAlertMoment() { + public void authenticateByAccessTokenInactive() { + testUtilsDao.deactivateUser(TestConstants.USERNAME_3); + + String accessTokenName = TestConstants.USERNAME_3_AT; + String accessTokenValue = TestConstants.USERNAME_3_AT_PASSWORD; + + // when + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByAuthenticationToken(accessTokenName, accessTokenValue)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("Login failed; Invalid userID or password!")); + } @Test - public void getLoginFailDelayInMilliSeconds() { + public void authenticateByAccessTokenCredentialsInactive() { + DBCredential credential = testUtilsDao.getUser3().getUserCredentials().get(0); + credential.setActive(false); + testUtilsDao.updateCredentials(credential); + + // given + String accessTokenName = TestConstants.USERNAME_3_AT; + String accessTokenValue = TestConstants.USERNAME_3_AT_PASSWORD; + + // when + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByAuthenticationToken(accessTokenName, accessTokenValue)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("Login failed; Invalid userID or password!")); + + } + + @Test + public void authenticateByAccessTokenSuspended() { + DBCredential credential = testUtilsDao.getUser3().getUserCredentials().get(0); + credential.setLastFailedLoginAttempt(OffsetDateTime.now()); + credential.setSequentialLoginFailureCount(100); + testUtilsDao.updateCredentials(credential); + + // given + String accessTokenName = TestConstants.USERNAME_3_AT; + String accessTokenValue = TestConstants.USERNAME_3_AT_PASSWORD; + + // when + BadCredentialsException result = assertThrows(BadCredentialsException.class, () -> testInstance.authenticateByAuthenticationToken(accessTokenName, accessTokenValue)); + MatcherAssert.assertThat(result.getMessage(), org.hamcrest.Matchers.startsWith("The user credential is suspended. Please try again later or contact your administrator.")); } + + @Test + public void authenticateByAccessTokenCredentialsNotSuspendedAnymore() { + DBCredential credential = testUtilsDao.getUser3().getUserCredentials().get(0); + credential.setLastFailedLoginAttempt(OffsetDateTime.now().minusDays(100)); + credential.setSequentialLoginFailureCount(100); + testUtilsDao.updateCredentials(credential); + + // given + String accessTokenName = TestConstants.USERNAME_3_AT; + String accessTokenValue = TestConstants.USERNAME_3_AT_PASSWORD; + // when then + Authentication authentication = testInstance.authenticateByAuthenticationToken(accessTokenName, accessTokenValue); + // then + assertEquals(TestConstants.USERNAME_3_AT, authentication.getName()); + } + } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestConstants.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestConstants.java index 7bc0eee99..8ae691e50 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestConstants.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestConstants.java @@ -45,8 +45,11 @@ public class TestConstants { public static final String TOKEN_PREFIX = "token-"; public static final String USERNAME_1 = "test-user_001"; + public static final String USERNAME_1_PASSWORD = "test-user_001"; public static final String USERNAME_2 = "test-user_002"; public static final String USERNAME_3 = "test-user_003"; + public static final String USERNAME_3_AT = "test-user_003-access-token"; + public static final String USERNAME_3_AT_PASSWORD = "test-user_003"; public static final String USERNAME_4 = "test-user_004"; public static final String USERNAME_5 = "test-user_005"; public static final String USERNAME_TOKEN_1 = TOKEN_PREFIX + USERNAME_1; -- GitLab