From 4b5c02cb3f9554332631a8b19253fe519a586257 Mon Sep 17 00:00:00 2001
From: Joze RIHTARSIC <joze.RIHTARSIC@ext.ec.europa.eu>
Date: Wed, 8 Jun 2022 09:04:53 +0200
Subject: [PATCH] Add unit tests

---
 .../smp/services/ui/UITruststoreService.java  |  57 ++++++--
 .../smp/services/ui/UIUserService.java        |  15 +-
 .../services/ui/UITruststoreServiceTest.java  |  50 ++++++-
 .../ui/UIUserServiceIntegrationTest.java      | 128 ++++++++++++++++++
 .../edelivery/smp/testutil/TestROUtils.java   |  36 +++--
 .../testutil/X509CertificateTestUtils.java    |  44 ++----
 .../smp/auth/SMPAuthenticationProvider.java   |  26 ++--
 7 files changed, 281 insertions(+), 75 deletions(-)

diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreService.java
index 747391c1d..ee0b595a5 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreService.java
@@ -1,5 +1,6 @@
 package eu.europa.ec.edelivery.smp.services.ui;
 
+import eu.europa.ec.edelivery.security.cert.CertificateValidator;
 import eu.europa.ec.edelivery.security.utils.X509CertificateUtils;
 import eu.europa.ec.edelivery.smp.data.dao.UserDao;
 import eu.europa.ec.edelivery.smp.data.model.DBUser;
@@ -72,7 +73,7 @@ public class UITruststoreService {
 
     Map<String, X509Certificate> truststoreCertificates = new HashMap();
     List<CertificateRO> certificateROList = new ArrayList<>();
-    long lastUpdateTrustoreFileTime = 0;
+    long lastUpdateTrustStoreFileTime = 0;
     File lastUpdateTrustStoreFile = null;
     TrustManager[] trustManagers;
     KeyStore trustStore = null;
@@ -164,7 +165,7 @@ public class UITruststoreService {
         normalizedTrustedList.addAll(tmpList);
         truststoreCertificates.putAll(hmCertificates);
 
-        lastUpdateTrustoreFileTime = truststoreFile.lastModified();
+        lastUpdateTrustStoreFileTime = truststoreFile.lastModified();
         lastUpdateTrustStoreFile = truststoreFile;
         // clear list to reload RO when required
         certificateROList.clear();
@@ -188,7 +189,7 @@ public class UITruststoreService {
         CertificateRO cro;
         try {
             cert = X509CertificateUtils.getX509Certificate(buff);
-        } catch ( Throwable e) {
+        } catch (Throwable e) {
             LOG.debug("Error occurred while parsing the certificate ", e);
             LOG.warn("Can not parse the certificate with error:[{}]!", ExceptionUtils.getRootCauseMessage(e));
             cro = new CertificateRO();
@@ -222,9 +223,33 @@ public class UITruststoreService {
         return cro;
     }
 
+    public void validateCertificateWithTruststore(X509Certificate x509Certificate) throws CertificateException {
+        KeyStore truststore = getTrustStore();
+
+        if (x509Certificate == null) {
+            LOG.warn("The X509Certificate is null (Is the client cert header enabled?)! Skip trust validation against the truststore!");
+            return;
+        }
+
+        if (truststore == null) {
+            LOG.warn("Truststore is not configured! Skip trust validation against the truststore!");
+            return;
+        }
+
+        Pattern subjectRegExp = configurationService.getCertificateSubjectRegularExpression();
+        List<String> allowedCertificatePolicies = configurationService.getAllowedCertificatePolicies();
+        CertificateValidator certificateValidator = new CertificateValidator(
+                null, truststore,
+                subjectRegExp != null ? subjectRegExp.pattern() : null,
+                configurationService.getAllowedCertificatePolicies());
+        LOG.debug("Validate certificate with truststore, subject regexp [{}] and allowed certificate policies [{}]", subjectRegExp, allowedCertificatePolicies);
+        certificateValidator.validateCertificate(x509Certificate);
+    }
+
     public void checkFullCertificateValidity(X509Certificate cert) throws CertificateException {
         // test if certificate is valid
         cert.checkValidity();
+
         // check if certificate or its issuer is on trusted list
         // check only issuer because using Client-cert header we do not have whole chain.
         // if the truststore is empty then truststore validation is ignored
@@ -234,8 +259,16 @@ public class UITruststoreService {
 
             throw new CertificateNotTrustedException("Certificate is not trusted!");
         }
-        validateCertificatePolicyMatch(cert);
-        validateCertificateSubjectExpression(cert);
+
+
+        if (trustStore!=null) {
+            validateCertificateWithTruststore(cert);
+        } else {
+            LOG.warn("Use legacy certificate validation without truststore. Please configure truststore to increase security");
+            validateCertificatePolicyMatchLegacy(cert);
+            validateCertificateSubjectExpressionLegacy(cert);
+        }
+
         // check CRL - it is using only HTTP or https
         crlVerifierService.verifyCertificateCRLs(cert);
     }
@@ -253,6 +286,7 @@ public class UITruststoreService {
 
     public void checkFullCertificateValidity(CertificateRO cert) throws CertificateException {
         // trust data in database
+
         Date currentDate = Calendar.getInstance().getTime();
         if (cert.getValidFrom() != null && currentDate.before(cert.getValidFrom())) {
             throw new CertificateNotYetValidException("Certificate: " + cert.getCertificateId() + " is valid from: "
@@ -294,7 +328,7 @@ public class UITruststoreService {
     boolean isTruststoreChanged() {
         File file = getTruststoreFile();
         return !Objects.equals(lastUpdateTrustStoreFile, file) ||
-                file != null && file.lastModified() != lastUpdateTrustoreFileTime;
+                file != null && file.lastModified() != lastUpdateTrustStoreFileTime;
     }
 
     public File getTruststoreFile() {
@@ -528,7 +562,14 @@ public class UITruststoreService {
                 .collect(Collectors.toList());
     }
 
-    protected void validateCertificatePolicyMatch(X509Certificate certificate) throws CertificateException {
+    /**
+     * Method validates if the certificate contains one of allowed Certificate policy. At the moment it does not validates
+     * the whole chain. Because in some configuration cases does not use the truststore
+     *
+     * @param certificate
+     * @throws CertificateException
+     */
+    protected void validateCertificatePolicyMatchLegacy(X509Certificate certificate) throws CertificateException {
 
         // allowed list
         List<String> allowedCertificatePolicyOIDList = configurationService.getAllowedCertificatePolicies();
@@ -552,7 +593,7 @@ public class UITruststoreService {
         throw new CertificateException(excMessage);
     }
 
-    protected void validateCertificateSubjectExpression(X509Certificate signingCertificate) throws CertificateException {
+    protected void validateCertificateSubjectExpressionLegacy(X509Certificate signingCertificate) throws CertificateException {
         LOG.debug("Validate certificate subject");
 
 
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java
index 0ac759a0d..481581aef 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java
@@ -77,6 +77,7 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
      * @return ServiceResult with list
      */
     @Transactional
+    @Override
     public ServiceResult<UserRO> getTableList(int page, int pageSize, String sortField, String sortOrder, Object filter) {
         ServiceResult<UserRO> resUsers = super.getTableList(page, pageSize, sortField, sortOrder, filter);
         resUsers.getServiceEntities().forEach(this::updateUserStatus);
@@ -191,10 +192,12 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
             LOG.error("Can not update user because user for id [{}] does not exist!", userId);
             throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "UserId", "Can not find user id!");
         }
-
         dbUser.setEmailAddress(user.getEmailAddress());
-        if (user.getCertificate() != null && (dbUser.getCertificate() == null
-                || !StringUtils.equals(dbUser.getCertificate().getCertificateId(), user.getCertificate().getCertificateId()))) {
+
+        if (user.getCertificate() != null &&
+                (dbUser.getCertificate() == null
+                        || !StringUtils.equals(dbUser.getCertificate().getCertificateId(), user.getCertificate().getCertificateId()))) {
+
             CertificateRO certRo = user.getCertificate();
 
             if (dbUser.getCertificate() != null) {
@@ -318,6 +321,12 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
     }
 
 
+    /**
+     * User can be deleted only if it does not own any of the service groups.
+     *
+     * @param dev
+     * @return
+     */
     public DeleteEntityValidation validateDeleteRequest(DeleteEntityValidation dev) {
         List<Long> idList = dev.getListIds().stream().map(encId -> SessionSecurityUtils.decryptEntityId(encId)).collect(Collectors.toList());
         List<DBUserDeleteValidation> lstMessages = userDao.validateUsersForDelete(idList);
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreServiceTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreServiceTest.java
index 2a30e0fbc..b3c72085f 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreServiceTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreServiceTest.java
@@ -10,6 +10,8 @@ import eu.europa.ec.edelivery.smp.services.ConfigurationService;
 import eu.europa.ec.edelivery.smp.testutil.X509CertificateTestUtils;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -24,13 +26,11 @@ import org.springframework.test.util.ReflectionTestUtils;
 import javax.security.auth.x500.X500Principal;
 import java.io.File;
 import java.io.IOException;
+import java.math.BigInteger;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.cert.*;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
+import java.util.*;
 
 import static org.junit.Assert.*;
 
@@ -38,6 +38,12 @@ import static org.junit.Assert.*;
 @RunWith(SpringJUnit4ClassRunner.class)
 public class UITruststoreServiceTest extends AbstractServiceIntegrationTest {
 
+    public static final String CERTIFICATE_POLICY_ANY="2.5.29.32.0";
+    public static final String CERTIFICATE_POLICY_QCP_NATURAL = "0.4.0.194112.1.0";
+    public static final String CERTIFICATE_POLICY_QCP_LEGAL = "0.4.0.194112.1.1";
+    public static final String CERTIFICATE_POLICY_QCP_NATURAL_QSCD = "0.4.0.194112.1.2";
+    public static final String CERTIFICATE_POLICY_QCP_LEGAL_QSCD = "0.4.0.194112.1.3";
+
     public static final String S_SUBJECT_PEPPOL = "CN=POP000004,OU=PEPPOL TEST AP,O=European Commission,C=BE";
     public static final String S_SUBJECT_PEPPOL_EXPANDED = "serialNumber=12345,emailAddress=test@mail.com,CN=POP000004,OU=PEPPOL TEST AP,O=European Commission,street=My Street,C=BE";
     public static final String S_SUBJECT_PEPPOL_NOT_TRUSTED = "CN=POP000005,OU=PEPPOL TEST AP,O=European Commission,C=BE";
@@ -178,12 +184,13 @@ public class UITruststoreServiceTest extends AbstractServiceIntegrationTest {
 
 
     @Test
-    public void testGetCertificateDataPEM() throws IOException, CertificateException {
+    public void testGetCertificateDataPEMAndFullValidationExpired() throws IOException{
         // given
+
         byte[] buff = IOUtils.toByteArray(UIUserServiceIntegrationTest.class.getResourceAsStream("/truststore/SMPtest.crt"));
 
         // when
-        CertificateRO cer = testInstance.getCertificateData(buff);
+        CertificateRO cer = testInstance.getCertificateData(buff, true);
 
         //then
         assertEquals("CN=SMP test,O=DIGIT,C=BE:0000000000000003", cer.getCertificateId());
@@ -193,6 +200,7 @@ public class UITruststoreServiceTest extends AbstractServiceIntegrationTest {
         assertNotNull(cer.getValidFrom());
         assertNotNull(cer.getValidTo());
         assertTrue(cer.getValidFrom().before(cer.getValidTo()));
+        assertEquals("Certificate is expired!",cer.getInvalidReason());
     }
 
     @Test
@@ -411,4 +419,34 @@ public class UITruststoreServiceTest extends AbstractServiceIntegrationTest {
         assertEquals("SMP Test", alias);
     }
 
+    @Test
+    public void testValidateCertificatePolicyLegacyMatchOk() throws Exception {
+        String certSubject = "CN=SMP Test,OU=eDelivery,O=DIGITAL,C=BE";
+        X509Certificate certificate = X509CertificateTestUtils.createX509CertificateForTest(certSubject, BigInteger.TEN, Arrays.asList(CERTIFICATE_POLICY_QCP_NATURAL));
+        Mockito.doReturn( Arrays.asList(CERTIFICATE_POLICY_QCP_LEGAL, CERTIFICATE_POLICY_QCP_NATURAL)).when(configurationService).getAllowedCertificatePolicies();
+        testInstance.validateCertificatePolicyMatchLegacy(certificate);
+    }
+
+    @Test
+    public void testValidateCertificatePolicyLegacyMatchEmpty() throws Exception {
+        String certSubject = "CN=SMP Test,OU=eDelivery,O=DIGITAL,C=BE";
+        X509Certificate certificate = X509CertificateTestUtils.createX509CertificateForTest(certSubject,BigInteger.TEN, null);
+        Mockito.doReturn( Arrays.asList(CERTIFICATE_POLICY_QCP_LEGAL, CERTIFICATE_POLICY_QCP_NATURAL)).when(configurationService).getAllowedCertificatePolicies();
+
+        CertificateException result = assertThrows(CertificateException.class,
+                () -> testInstance.validateCertificatePolicyMatchLegacy(certificate));
+        MatcherAssert.assertThat(result.getMessage(), CoreMatchers.startsWith("Certificate has empty CertificatePolicy extension. Certificate:"));
+    }
+
+    @Test
+    public void testValidateCertificatePolicyLegacyMatchMismatch() throws Exception {
+        String certSubject = "CN=SMP Test,OU=eDelivery,O=DIGITAL,C=BE";
+        X509Certificate certificate = X509CertificateTestUtils.createX509CertificateForTest(certSubject,BigInteger.TEN, Arrays.asList(CERTIFICATE_POLICY_QCP_LEGAL_QSCD));
+        Mockito.doReturn( Arrays.asList(CERTIFICATE_POLICY_QCP_LEGAL, CERTIFICATE_POLICY_QCP_NATURAL)).when(configurationService).getAllowedCertificatePolicies();
+
+        CertificateException result = assertThrows(CertificateException.class,
+                () -> testInstance.validateCertificatePolicyMatchLegacy(certificate));
+        MatcherAssert.assertThat(result.getMessage(), CoreMatchers.startsWith("Certificate policy verification failed."));
+    }
+
 }
\ No newline at end of file
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java
index c6d61ec30..2c2f2bf51 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java
@@ -9,16 +9,23 @@ import eu.europa.ec.edelivery.smp.data.ui.CertificateRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
 import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
+import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
 import eu.europa.ec.edelivery.smp.services.AbstractServiceIntegrationTest;
 import eu.europa.ec.edelivery.smp.testutil.TestDBUtils;
+import eu.europa.ec.edelivery.smp.testutil.TestROUtils;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.crypto.bcrypt.BCrypt;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigInteger;
 import java.time.OffsetDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
@@ -296,4 +303,125 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest
         assertNotNull(result.getAccessTokenGeneratedOn());
     }
 
+    @Test
+    public void testUpdateUserPasswordNotMatchReqExpression() {
+        long authorizedUserId = 1L;
+        long userToUpdateId = 1L;
+        String authorizedPassword="testPass";
+        String newPassword="newPass";
+
+        SMPRuntimeException result = assertThrows(SMPRuntimeException.class,
+                () -> testInstance.updateUserPassword(authorizedUserId, userToUpdateId, authorizedPassword, newPassword));
+
+        MatcherAssert.assertThat(result.getMessage(), CoreMatchers.containsString("Invalid request PasswordChange."));
+    }
+
+    @Test
+    public void testUpdateUserPasswordUserNotExists() {
+
+        long authorizedUserId = 1L;
+        long userToUpdateId = 1L;
+        String authorizedPassword="oldPass";
+        String newPassword="TTTTtttt1111$$$$$";
+
+        SMPRuntimeException result = assertThrows(SMPRuntimeException.class,
+                () -> testInstance.updateUserPassword(authorizedUserId, userToUpdateId, authorizedPassword, newPassword));
+
+        MatcherAssert.assertThat(result.getMessage(), CoreMatchers.containsString("Invalid request UserId.  Error: Can not find user id!"));
+    }
+
+    @Test
+    public void testUpdateUserPasswordUserNotAuthorized() {
+        String userPassword = UUID.randomUUID().toString();
+        DBUser user = new DBUser();
+        user.setPassword(BCrypt.hashpw(userPassword, BCrypt.gensalt()));
+        user.setUsername(UUID.randomUUID().toString());
+        user.setEmailAddress(UUID.randomUUID().toString());
+        user.setRole("ROLE");
+        userDao.persistFlushDetach(user);
+
+        long authorizedUserId = user.getId();
+        long userToUpdateId = 1L;
+        String authorizedPassword="oldPass";
+        String newPassword="TTTTtttt1111$$$$$";
+
+        BadCredentialsException result = assertThrows(BadCredentialsException.class,
+                () -> testInstance.updateUserPassword(authorizedUserId, userToUpdateId, authorizedPassword, newPassword));
+
+        MatcherAssert.assertThat(result.getMessage(), CoreMatchers.containsString("Password change failed; Invalid current password!"));
+    }
+
+    @Test
+    public void testUpdateUserPasswordOK() {
+        String userPassword = UUID.randomUUID().toString();
+        DBUser user = new DBUser();
+        user.setPassword(BCrypt.hashpw(userPassword, BCrypt.gensalt()));
+        user.setUsername(UUID.randomUUID().toString());
+        user.setEmailAddress(UUID.randomUUID().toString());
+        user.setRole("ROLE");
+        userDao.persistFlushDetach(user);
+
+        long authorizedUserId = user.getId();
+        long userToUpdateId = user.getId();
+        String authorizedPassword=userPassword;
+        String newPassword="TTTTtttt1111$$$$$";
+
+        testInstance.updateUserPassword(authorizedUserId, userToUpdateId, authorizedPassword, newPassword);
+    }
+
+    @Test
+    public void testUpdateUserdataOK() {
+        String userPassword = UUID.randomUUID().toString();
+        DBUser user = new DBUser();
+        user.setPassword(BCrypt.hashpw(userPassword, BCrypt.gensalt()));
+        user.setUsername(UUID.randomUUID().toString());
+        user.setEmailAddress(UUID.randomUUID().toString());
+        user.setRole("ROLE");
+        userDao.persistFlushDetach(user);
+
+        UserRO userRO = new UserRO();
+        userRO.setEmailAddress(UUID.randomUUID().toString());
+        userRO.setUsername(UUID.randomUUID().toString());
+        userRO.setAccessTokenId(UUID.randomUUID().toString());
+        userRO.setRole(UUID.randomUUID().toString());
+
+        testInstance.updateUserdata(user.getId(), userRO);
+
+        DBUser changedUser = userDao.findUser(user.getId()).get();
+        // fields must not change
+        assertEquals(user.getUsername(), changedUser.getUsername());
+        assertEquals(user.getAccessToken(), changedUser.getAccessToken());
+        assertEquals(user.getRole(), changedUser.getRole());
+        // changed
+        assertEquals(userRO.getEmailAddress(), changedUser.getEmailAddress());
+    }
+
+    @Test
+    public void testUpdateUserdataCertificateOK() throws Exception {
+        String certSubject = "CN="+UUID.randomUUID().toString()+",O=eDelivery,C=EU";
+        String userPassword = UUID.randomUUID().toString();
+        DBUser user = new DBUser();
+        user.setPassword(BCrypt.hashpw(userPassword, BCrypt.gensalt()));
+        user.setUsername(UUID.randomUUID().toString());
+        user.setEmailAddress(UUID.randomUUID().toString());
+        user.setRole("ROLE");
+        userDao.persistFlushDetach(user);
+
+        CertificateRO certificateRO = TestROUtils.createCertificateRO(certSubject, BigInteger.TEN);
+        UserRO userRO = new UserRO();
+        userRO.setCertificate(certificateRO);;
+        testInstance.updateUserdata(user.getId(), userRO);
+
+
+        DBUser changedUser = userDao.findUser(user.getId()).get();
+        // fields must not change
+        assertNotNull(changedUser.getCertificate());
+        assertNotNull(changedUser.getCertificate().getPemEncoding());
+        assertNotNull(certificateRO.getCertificateId(),changedUser.getCertificate().getCertificateId());
+        assertNotNull(certificateRO.getSubject(),changedUser.getCertificate().getSubject());
+        assertNotNull(certificateRO.getIssuer(),changedUser.getCertificate().getIssuer());
+        assertNotNull(certificateRO.getSerialNumber(),changedUser.getCertificate().getSerialNumber());
+
+
+    }
 }
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestROUtils.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestROUtils.java
index f107f79b3..c9158a142 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestROUtils.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestROUtils.java
@@ -1,13 +1,13 @@
 package eu.europa.ec.edelivery.smp.testutil;
 
+import eu.europa.ec.edelivery.smp.conversion.X509CertificateToCertificateROConverter;
 import eu.europa.ec.edelivery.smp.data.model.DBDomain;
-import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupDomainRO;
-import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupValidationRO;
-import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupRO;
-import eu.europa.ec.edelivery.smp.data.ui.ServiceMetadataRO;
+import eu.europa.ec.edelivery.smp.data.ui.*;
 import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
 
 import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import java.util.UUID;
 
@@ -17,18 +17,20 @@ import static eu.europa.ec.edelivery.smp.testutil.TestConstants.SIMPLE_EXTENSION
 
 public class TestROUtils {
 
+    public static final X509CertificateToCertificateROConverter CERT_CONVERTER = new X509CertificateToCertificateROConverter();
 
-    public static ServiceMetadataRO createServiceMetadataDomain(DBDomain domain, ServiceGroupRO sgo, String docid, String docSch){
+
+    public static ServiceMetadataRO createServiceMetadataDomain(DBDomain domain, ServiceGroupRO sgo, String docid, String docSch) {
         ServiceMetadataRO sgdmd = new ServiceMetadataRO();
         sgdmd.setDomainCode(domain.getDomainCode());
         sgdmd.setSmlSubdomain(domain.getSmlSubdomain());
         sgdmd.setDocumentIdentifier(docid);
         sgdmd.setDocumentIdentifierScheme(docSch);
-        sgdmd.setXmlContent(generateServiceMetadata(sgo.getParticipantIdentifier(), sgo.getParticipantScheme(), docid,docSch ));
+        sgdmd.setXmlContent(generateServiceMetadata(sgo.getParticipantIdentifier(), sgo.getParticipantScheme(), docid, docSch));
         return sgdmd;
     }
 
-    public static ServiceGroupDomainRO createServiceGroupDomain(DBDomain domain){
+    public static ServiceGroupDomainRO createServiceGroupDomain(DBDomain domain) {
 
         ServiceGroupDomainRO sgd = new ServiceGroupDomainRO();
         sgd.setDomainId(domain.getId());
@@ -41,8 +43,8 @@ public class TestROUtils {
         return createROServiceGroup(TestConstants.TEST_SG_ID_1, TestConstants.TEST_SG_SCHEMA_1);
     }
 
-    public static ServiceGroupRO createROServiceGroupForDomains(DBDomain ... domains) {
-        ServiceGroupRO sgo =  createROServiceGroup(TestConstants.TEST_SG_ID_1, TestConstants.TEST_SG_SCHEMA_1);
+    public static ServiceGroupRO createROServiceGroupForDomains(DBDomain... domains) {
+        ServiceGroupRO sgo = createROServiceGroup(TestConstants.TEST_SG_ID_1, TestConstants.TEST_SG_SCHEMA_1);
         Arrays.asList(domains).forEach(domain -> {
             ServiceGroupDomainRO sgd = createServiceGroupDomain(domain);
             sgo.getServiceGroupDomains().add(sgd);
@@ -50,8 +52,8 @@ public class TestROUtils {
         return sgo;
     }
 
-    public static ServiceGroupRO createROServiceGroupForDomains(String id, String sch, DBDomain ... domains) {
-        ServiceGroupRO sgo =  createROServiceGroup(id, sch);
+    public static ServiceGroupRO createROServiceGroupForDomains(String id, String sch, DBDomain... domains) {
+        ServiceGroupRO sgo = createROServiceGroup(id, sch);
         Arrays.asList(domains).forEach(domain -> {
             ServiceGroupDomainRO sgd = createServiceGroupDomain(domain);
             sgo.getServiceGroupDomains().add(sgd);
@@ -75,12 +77,12 @@ public class TestROUtils {
         return grp;
     }
 
-    public static String generateExtension(){
+    public static String generateExtension() {
         return String.format(SIMPLE_EXTENSION_XML, UUID.randomUUID().toString());
     }
 
-    public static String generateServiceMetadata(String partId, String partSch, String docId, String docSch){
-        return String.format(SIMPLE_DOCUMENT_XML, partSch, partId,docSch, docId, UUID.randomUUID().toString()  );
+    public static String generateServiceMetadata(String partId, String partSch, String docId, String docSch) {
+        return String.format(SIMPLE_DOCUMENT_XML, partSch, partId, docSch, docId, UUID.randomUUID().toString());
     }
 
     public static ServiceGroupValidationRO getValidExtension() throws IOException {
@@ -116,4 +118,10 @@ public class TestROUtils {
         sg.setExtension(extension);
         return sg;
     }
+
+
+    public static CertificateRO createCertificateRO(String certSubject, BigInteger serial) throws Exception {
+        X509Certificate cert = X509CertificateTestUtils.createX509CertificateForTest(certSubject, serial, null);
+        return CERT_CONVERTER.convert(cert);
+    }
 }
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/X509CertificateTestUtils.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/X509CertificateTestUtils.java
index 570354e4e..f02a0a01a 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/X509CertificateTestUtils.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/X509CertificateTestUtils.java
@@ -1,5 +1,6 @@
 package eu.europa.ec.edelivery.smp.testutil;
 
+import eu.europa.ec.edelivery.security.utils.X509CertificateUtils;
 import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x509.*;
 import org.bouncycastle.cert.X509v3CertificateBuilder;
@@ -14,6 +15,7 @@ import java.security.KeyPairGenerator;
 import java.security.KeyStore;
 import java.security.PrivateKey;
 import java.security.cert.X509Certificate;
+import java.time.OffsetDateTime;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -77,40 +79,18 @@ public class X509CertificateTestUtils {
         return certs;
     }
 
-    /**
-     *  Method generates certificate chain
-     * @param subjects
-     * @param certificatePoliciesOids
-     * @param startDate
-     * @param expiryDate
-     * @return
-     * @throws Exception
-     */
-    public static X509Certificate[] createCertificateChain(String[] subjects,  List<List<String>> certificatePoliciesOids,  Date startDate, Date expiryDate) throws Exception {
 
-        String issuer = null;
-        PrivateKey issuerKey = null;
-        long iSerial = 10000;
-        X509Certificate[] certs = new X509Certificate[subjects.length];
-
-        int index = subjects.length;
-        for (String sbj: subjects){
-            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
-            keyGen.initialize(1024);
-            KeyPair key = keyGen.generateKeyPair();
-
-            X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(new X500Name(issuer ==null? sbj:issuer),
-                    BigInteger.valueOf(iSerial++), startDate, expiryDate, new X500Name(sbj),
-                    SubjectPublicKeyInfo.getInstance(key.getPublic().getEncoded()));
-
-            ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WITHRSA")
-                    .setProvider("BC").build(issuerKey ==null?key.getPrivate():issuerKey);
 
-            certs[--index] = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certBuilder.build(sigGen));
-            issuer= sbj;
-            issuerKey = key.getPrivate();
+    public static X509Certificate createX509CertificateForTest( String subject, BigInteger serial,  List<String> listOfPolicyOIDs) throws Exception {
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        KeyPair key = keyGen.generateKeyPair();
+        KeyUsage usage = new KeyUsage(244);
+        X509Certificate cert = X509CertificateUtils.createCertificate(serial,
+                key.getPublic(), subject, OffsetDateTime.now().minusDays(1L),
+                OffsetDateTime.now().plusYears(5L), (String)null,
+                key.getPrivate(), false, -1, usage, "SHA256withRSA",listOfPolicyOIDs);
 
-        }
-        return certs;
+        return cert;
     }
 }
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java
index fc4fa5f2d..dabd7ab4c 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java
@@ -1,11 +1,9 @@
 package eu.europa.ec.edelivery.smp.auth;
 
 import eu.europa.ec.edelivery.security.PreAuthenticatedCertificatePrincipal;
-import eu.europa.ec.edelivery.security.cert.CertificateValidator;
 import eu.europa.ec.edelivery.smp.data.dao.UserDao;
 import eu.europa.ec.edelivery.smp.data.model.DBCertificate;
 import eu.europa.ec.edelivery.smp.data.model.DBUser;
-import eu.europa.ec.edelivery.smp.data.ui.UserRO;
 import eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority;
 import eu.europa.ec.edelivery.smp.data.ui.enums.AlertSuspensionMomentEnum;
 import eu.europa.ec.edelivery.smp.data.ui.enums.CredentialTypeEnum;
@@ -99,9 +97,9 @@ public class SMPAuthenticationProvider implements AuthenticationProvider {
                 LOG.warn("Unknown or null PreAuthenticatedAuthenticationToken principal type: " + principal);
             }
         } else if (authenticationToken instanceof UsernamePasswordAuthenticationToken) {
-            LOG.info("try to authentication Token: [{}] with user:[{}]" , authenticationToken.getClass(), authenticationToken.getPrincipal());
-            if (CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER.equalsIgnoreCase((String)authenticationToken.getPrincipal())
-             || CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER.equalsIgnoreCase((String)authenticationToken.getPrincipal())){
+            LOG.info("try to authentication Token: [{}] with user:[{}]", authenticationToken.getClass(), authenticationToken.getPrincipal());
+            if (CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER.equalsIgnoreCase((String) authenticationToken.getPrincipal())
+                    || CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER.equalsIgnoreCase((String) authenticationToken.getPrincipal())) {
                 LOG.debug("Ignore CAS authentication and leave it to cas authentication module");
                 return null;
             }
@@ -133,13 +131,15 @@ public class SMPAuthenticationProvider implements AuthenticationProvider {
         X509Certificate x509Certificate = principal.getCertificate();
         String userToken = principal.getName();
 
-        if (truststore != null && x509Certificate != null) {
-            CertificateValidator certificateValidator = new CertificateValidator(
-                    null, truststore, null);
+
+        if (x509Certificate != null) {
             try {
-                certificateValidator.validateCertificate(x509Certificate);
+                truststoreService.validateCertificateWithTruststore(x509Certificate);
             } catch (CertificateException e) {
-                throw new BadCredentialsException("Certificate is not trusted!");
+                String message = "Certificate is not trusted!";
+                LOG.securityWarn(SMPMessageCode.SEC_USER_CERT_INVALID, userToken , message
+                        + " The cert chain is not in truststore or either subject regexp or allowed cert policies does not match");
+                throw new BadCredentialsException(message);
             }
         }
 
@@ -163,6 +163,7 @@ public class SMPAuthenticationProvider implements AuthenticationProvider {
         DBCertificate certificate = user.getCertificate();
         // check if certificate is valid
         Date currentDate = Calendar.getInstance().getTime();
+        // this is legacy code because some setups does not have truststore configured
         // validate  dates
         if (principal.getNotBefore() == null) {
             String msg = "Invalid certificate configuration: 'Not Before' value is missing!";
@@ -181,6 +182,7 @@ public class SMPAuthenticationProvider implements AuthenticationProvider {
             LOG.securityWarn(SMPMessageCode.SEC_USER_CERT_INVALID, userToken, msg);
             throw new AuthenticationServiceException(msg);
         }
+
         // check if issuer or subject are in trusted list
         if (!(truststoreService.isSubjectOnTrustedList(principal.getSubjectOriginalDN())
                 || truststoreService.isSubjectOnTrustedList(principal.getIssuerDN()))) {
@@ -217,7 +219,7 @@ public class SMPAuthenticationProvider implements AuthenticationProvider {
 
 
     public void delayResponse(long startTime) {
-        int delayInMS = configurationService.getAccessTokenLoginFailDelayInMilliSeconds() -  (int) (Calendar.getInstance().getTimeInMillis() - startTime);
+        int delayInMS = configurationService.getAccessTokenLoginFailDelayInMilliSeconds() - (int) (Calendar.getInstance().getTimeInMillis() - startTime);
         if (delayInMS > 0) {
             try {
                 LOG.debug("Delay response for [{}] ms to mask password/username login failures!", delayInMS);
@@ -317,7 +319,7 @@ public class SMPAuthenticationProvider implements AuthenticationProvider {
         // the webservice authentication with corresponding web-service authority;
         SMPAuthority authority = SMPAuthority.getAuthorityByRoleName("WS_" + user.getRole());
         // the webservice authentication does not support session set the session secret is null!
-        SMPUserDetails userDetails = new SMPUserDetails(user, null,  Collections.singletonList(authority));
+        SMPUserDetails userDetails = new SMPUserDetails(user, null, Collections.singletonList(authority));
 
         SMPAuthenticationToken smpAuthenticationToken = new SMPAuthenticationToken(authenticationTokenId,
                 authenticationTokenValue,
-- 
GitLab