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