From 3407cff2b20687a247ae3273c09b2ac9f27a2040 Mon Sep 17 00:00:00 2001 From: Joze RIHTARSIC <joze.rihtarsic@ext.ec.europa.eu> Date: Tue, 27 Nov 2018 21:23:26 +0100 Subject: [PATCH] - sml integration fix --- smp-angular/src/app/app.module.ts | 2 + .../src/app/domain/domain.component.ts | 47 ++++- .../src/app/domain/sml-integration.service.ts | 28 +++ .../smp/data/dao/ServiceGroupDao.java | 28 +++ .../smp/data/model/DBServiceGroupDomain.java | 5 + .../edelivery/smp/services/DomainService.java | 69 ++++++- .../smp/services/ui/UIDomainService.java | 15 +- .../edelivery/smp/sml/SmlClientFactory.java | 20 +- .../ec/edelivery/smp/sml/SmlConnector.java | 14 +- .../edelivery/smp/utils/SMPPropertyEnum.java | 4 + .../AbstractServiceIntegrationTest.java | 2 +- .../DomainServiceIntegrationTest.java | 183 +++++++++++++++++- ...nticationByClientCertFromKeystoreTest.java | 6 +- ...henticationByClientCertHttpHeaderTest.java | 19 +- .../smp/config/PropertiesConfig.java | 57 +++++- .../edelivery/smp/ui/ApplicationResource.java | 34 ++-- .../ec/edelivery/smp/ui/DomainResource.java | 38 ++++ .../ec/edelivery/smp/ui/KeystoreResource.java | 2 +- .../src/main/resources/application.properties | 3 + .../src/main/resources/config.properties | 4 - .../smp/config/PropertiesTestConfig.java | 26 +-- .../smp/ui/ApplicationResourceTest.java | 38 +++- .../smp/ui/KeystoreResourceTest.java | 91 +++++++++ 23 files changed, 662 insertions(+), 73 deletions(-) create mode 100644 smp-angular/src/app/domain/sml-integration.service.ts create mode 100644 smp-webapp/src/main/resources/application.properties create mode 100644 smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/KeystoreResourceTest.java diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts index b8c662cb3..dcdb47728 100644 --- a/smp-angular/src/app/app.module.ts +++ b/smp-angular/src/app/app.module.ts @@ -84,6 +84,7 @@ import {KeystoreEditDialogComponent} from "./domain/keystore-edit-dialog/keystor import {KeystoreCertificateDialogComponent} from "./domain/keystore-certificate-dialog/keystore-certificate-dialog.component"; import {InformationDialogComponent} from "./common/information-dialog/information-dialog.component"; import {KeystoreService} from "./domain/keystore.service"; +import {SmlIntegrationService} from "./domain/sml-integration.service"; @NgModule({ declarations: [ @@ -183,6 +184,7 @@ import {KeystoreService} from "./domain/keystore.service"; DownloadService, CertificateService, KeystoreService, + SmlIntegrationService, GlobalLookups, DatePipe, UserService, diff --git a/smp-angular/src/app/domain/domain.component.ts b/smp-angular/src/app/domain/domain.component.ts index e9bb5f445..ac87020b7 100644 --- a/smp-angular/src/app/domain/domain.component.ts +++ b/smp-angular/src/app/domain/domain.component.ts @@ -15,6 +15,8 @@ import {SearchTableEntityStatus} from "../common/search-table/search-table-entit import {KeystoreEditDialogComponent} from "./keystore-edit-dialog/keystore-edit-dialog.component"; import {SmpInfoService} from "../app-info/smp-info.service"; import {SmpInfo} from "../app-info/smp-info.model"; +import {SmlIntegrationService} from "./sml-integration.service"; +import {KeystoreResult} from "./keystore-result.model"; @Component({ moduleId: module.id, @@ -40,6 +42,7 @@ export class DomainComponent implements OnInit { constructor(public securityService: SecurityService, protected smpInfoService: SmpInfoService, + protected smlIntegrationService:SmlIntegrationService, protected lookups: GlobalLookups, protected http: HttpClient, protected alertService: AlertService, @@ -173,6 +176,27 @@ export class DomainComponent implements OnInit { }) } + smlUnregisterDomain(domainCode:string){ + this.smlIntegrationService.unregisterDomainToSML$(domainCode).subscribe((res) => { + if (res) { + if (res.errorMessage){ + this.alertService.exception("Error occurred while unregistering domain:" + domainCode , res.errorMessage, false); + } else { + this.alertService.success("Domain " + domainCode + " unregistering to sml!"); + this.lookups.refreshDomainLookup(); + + } + } else { + this.alertService.exception("Error occurred while unregistering domain:" + domainCode , "Unknown Error", false); + } + }, + err => { + this.alertService.exception('Error occurred while unregistering domain:' + domainCode , err); + } + ) + + } + smlRegisterSelectedDomain() { if (this.searchTable.selected.length !== 1) { return false; @@ -187,11 +211,32 @@ export class DomainComponent implements OnInit { } }).afterClosed().subscribe(result => { if (result) { - domainRo.smlRegistered=true; + this.smlRegisterDomain(domainRo.domainCode); } }) } + smlRegisterDomain(domainCode:string){ + this.smlIntegrationService.registerDomainToSML$(domainCode).subscribe((res) => { + if (res) { + if (res.errorMessage){ + this.alertService.exception("Error occurred while registering domain:" + domainCode , res.errorMessage, false); + } else { + this.alertService.success("Domain " + domainCode + " registered to sml!"); + this.lookups.refreshDomainLookup(); + + } + } else { + this.alertService.exception("Error occurred while registering domain:" + domainCode , "Unknown Error", false); + } + }, + err => { + this.alertService.exception('Error occurred while registering domain:' + domainCode , err); + } + ) + + } + openEditKeystoreDialog() { const formRef: MatDialogRef<any> = this.dialog.open(KeystoreEditDialogComponent); formRef.afterClosed().subscribe(result => { diff --git a/smp-angular/src/app/domain/sml-integration.service.ts b/smp-angular/src/app/domain/sml-integration.service.ts new file mode 100644 index 000000000..170c594f7 --- /dev/null +++ b/smp-angular/src/app/domain/sml-integration.service.ts @@ -0,0 +1,28 @@ +import {Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; + +import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; +import {SmpConstants} from "../smp.constants"; +import {SecurityService} from "../security/security.service"; +import {User} from "../security/user.model"; +import {KeystoreResult} from "./keystore-result.model"; + +@Injectable() +export class SmlIntegrationService { + + constructor( + private http: HttpClient, + private securityService: SecurityService) { + } + + registerDomainToSML$(domainCode): Observable<KeystoreResult> { + + const currentUser: User = this.securityService.getCurrentUser(); + return this.http.post<KeystoreResult>(`${SmpConstants.REST_DOMAIN}/${currentUser.id}/smlregister/${domainCode}`, {}); + } + + unregisterDomainToSML$(domainCode): Observable<KeystoreResult> { + const currentUser: User = this.securityService.getCurrentUser(); + return this.http.post(`${SmpConstants.REST_DOMAIN}/${currentUser.id}/smlunregister/${domainCode}`,{}); + } +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java index e7027ca35..39c90f718 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java @@ -60,6 +60,34 @@ public class ServiceGroupDao extends BaseDao<DBServiceGroup> { } } + /** + * Method returns ServiceGroupDomain for participant identifie and domain code. If there is no service group + * or service group registred to domain it returns empty Option. + * If more than one result returns IllegalStateException caused by database data inconsistency. Only one combination of + * participant identifier must be in the database. + * + * @param participantId participant identifier + * @param schema participant identifier schema + * @param domainCode domainCode + * @return DBServiceGroup + */ + public Optional<DBServiceGroupDomain> findServiceGroupDomain(String participantId, String schema, String domainCode) { + + + try { + TypedQuery<DBServiceGroupDomain> query = memEManager.createNamedQuery("DBServiceGroupDomain.getServiceGroupDomain", DBServiceGroupDomain.class); + query.setParameter("participantIdentifier", participantId); + query.setParameter("participantScheme", schema); + query.setParameter("domainCode", domainCode); + DBServiceGroupDomain res = query.getSingleResult(); + return Optional.of(res); + } catch (NoResultException e) { + return Optional.empty(); + } catch (NonUniqueResultException e) { + throw new IllegalStateException(ErrorCode.ILLEGAL_STATE_SG_MULTIPLE_ENTRY.getMessage(participantId, schema)); + } + } + /** * Method removes service group from DB. Related entities:Extension, ownerships, * metadata clobs, metadata are also deleted. diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java index 3f61f7926..0969db1cc 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java @@ -16,6 +16,11 @@ import java.util.Objects; @Entity @Audited @Table(name = "SMP_SERVICE_GROUP_DOMAIN") +@NamedNativeQueries({ + @NamedNativeQuery(name = "DBServiceGroupDomain.getServiceGroupDomain", query = "SELECT sgd.* FROM SMP_DOMAIN dmn INNER JOIN SMP_SERVICE_GROUP_DOMAIN sgd ON sgd.FK_DOMAIN_ID = dmn.id " + + " INNER JOIN SMP_SERVICE_GROUP sg ON sg.ID = sgd.FK_SG_ID " + + " where sg.PARTICIPANT_IDENTIFIER = :participantIdentifier AND sg.PARTICIPANT_SCHEME=:participantScheme and dmn.DOMAIN_CODE =:domainCode", resultClass=DBServiceGroupDomain.class) +}) public class DBServiceGroupDomain extends BaseEntity { diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/DomainService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/DomainService.java index 5a3823b51..35b0eeeba 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/DomainService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/DomainService.java @@ -1,22 +1,36 @@ package eu.europa.ec.edelivery.smp.services; +import eu.europa.ec.edelivery.smp.conversion.CaseSensitivityNormalizer; import eu.europa.ec.edelivery.smp.data.dao.DomainDao; +import eu.europa.ec.edelivery.smp.data.dao.ServiceGroupDao; import eu.europa.ec.edelivery.smp.data.model.DBDomain; +import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup; +import eu.europa.ec.edelivery.smp.data.model.DBServiceGroupDomain; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; +import eu.europa.ec.edelivery.smp.logging.SMPLogger; +import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; +import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter; +import eu.europa.ec.edelivery.smp.sml.SmlConnector; import org.apache.commons.lang3.StringUtils; +import org.oasis_open.docs.bdxr.ns.smp._2016._05.ParticipantIdentifierType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.validation.constraints.NotNull; +import java.util.List; import java.util.Optional; import java.util.regex.Pattern; import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.*; +import static eu.europa.ec.edelivery.smp.logging.SMPMessageCode.BUS_SML_REGISTER_SERVICE_GROUP; +import static eu.europa.ec.edelivery.smp.logging.SMPMessageCode.BUS_SML_REGISTER_SERVICE_GROUP_ALREADY_REGISTERED; +import static eu.europa.ec.edelivery.smp.logging.SMPMessageCode.BUS_SML_REGISTER_SERVICE_GROUP_FAILED; /** - * Service group domain + * Service for domain * @author Joze Rihtarsic * @since 4.1 */ @@ -24,12 +38,21 @@ import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.*; @Service public class DomainService { + private static final SMPLogger LOG = SMPLoggerFactory.getLogger(DomainService.class); + public static final Pattern DOMAIN_ID_PATTERN = Pattern.compile("[a-zA-Z0-9]{1,50}"); + @Autowired + private SMLIntegrationService smlIntegrationService; + + @Autowired + private ServiceGroupDao serviceGroupDao; + @Autowired private DomainDao domainDao; + /** * Method checks if domain is in right format. Domain must contains only alphanomeric chars and it shoud * not be longer than 50 chars. @@ -57,4 +80,48 @@ public class DomainService { } return domEntity.get(); } + + /** + * If domain is not yet registered and sml integration is on. Than it tries to register domain and all participants + * on that domain. If integration is off it return an configuration exception. + * + * Method is not in transaction - but sub-methods are. if registering domain or particular serviceGroup succeed + * then the database flag (SML_REGISTERED) is turned on ( if method fails + * while execution the SML_REGISTERED reflect the real status in SML). Running the method again updates only + * serviceGroup which are not yet registered. + * + * + * @param domain + */ + + public void registerDomainAndParticipants(DBDomain domain){ + + smlIntegrationService.registerDomain(domain); + // get all participant for domain and register them + ServiceGroupFilter serviceGroupFilter = new ServiceGroupFilter(); + serviceGroupFilter.setDomain(domain); + + // register all service groups + List<DBServiceGroup> serviceGroupList = serviceGroupDao.getServiceGroupList(-1, -1, null, null, serviceGroupFilter); + for (DBServiceGroup sg: serviceGroupList){ + + smlIntegrationService.registerParticipant(sg.getParticipantIdentifier(), sg.getParticipantScheme(), domain.getDomainCode()); + } + } + + public void unregisterDomainAndParticipantsFromSml(DBDomain domain){ + + // get all participant for domain and register them + ServiceGroupFilter serviceGroupFilter = new ServiceGroupFilter(); + serviceGroupFilter.setDomain(domain); + + // register all service groups + List<DBServiceGroup> serviceGroupList = serviceGroupDao.getServiceGroupList(-1, -1, null, null, serviceGroupFilter); + for (DBServiceGroup sg: serviceGroupList){ + smlIntegrationService.unregisterParticipant(sg.getParticipantIdentifier(), sg.getParticipantScheme(), domain.getDomainCode()); + } + + smlIntegrationService.unRegisterDomain(domain); + } + } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainService.java index b1e61b6e1..a890d00a0 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainService.java @@ -9,6 +9,8 @@ import eu.europa.ec.edelivery.smp.data.ui.DeleteEntityValidation; import eu.europa.ec.edelivery.smp.data.ui.DomainRO; import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus; +import eu.europa.ec.edelivery.smp.logging.SMPLogger; +import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.sml.SmlConnector; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -18,10 +20,12 @@ import org.springframework.transaction.annotation.Transactional; import java.io.StringWriter; import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; @Service public class UIDomainService extends UIServiceBase<DBDomain, DomainRO> { + private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIDomainService.class); @Autowired DomainDao domainDao; @@ -55,8 +59,6 @@ public class UIDomainService extends UIServiceBase<DBDomain, DomainRO> { public void updateDomainList(List<DomainRO> lst) { boolean suc = false; for (DomainRO dRo: lst){ - - if (dRo.getStatus() == EntityROStatus.NEW.getStatusNumber()) { DBDomain dDb = convertFromRo(dRo); domainDao.persistFlushDetach(dDb); @@ -99,13 +101,4 @@ public class UIDomainService extends UIServiceBase<DBDomain, DomainRO> { return dev; } - public void registerDomainToSml(){ - - // smlConnector.registerInDns() - - // get participants for domain - - - } - } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/sml/SmlClientFactory.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/sml/SmlClientFactory.java index 7f489efb8..ca4be757e 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/sml/SmlClientFactory.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/sml/SmlClientFactory.java @@ -39,6 +39,7 @@ import javax.net.ssl.KeyManagerFactory; import javax.xml.ws.BindingProvider; import javax.xml.ws.handler.MessageContext; import java.io.FileInputStream; +import java.net.MalformedURLException; import java.net.URL; import java.security.KeyStore; import java.util.HashMap; @@ -96,9 +97,17 @@ public class SmlClientFactory { IManageParticipantIdentifierWS smlPort = smlService.getManageBusinessIdentifierServicePort(); Client client = ClientProxy.getClient(smlPort); + URL urlParticipantIdentifier; + try { + urlParticipantIdentifier = new URL(smlUrl.getProtocol(), smlUrl.getHost(), smlUrl.getPort(), smlUrl.getFile() + "/manageparticipantidentifier", null); + } catch (MalformedURLException e) { + throw new IllegalStateException("Could not create participant URL: " + smlUrl.toString(), e); + } + + HTTPConduit httpConduit = (HTTPConduit) client.getConduit(); Map<String, Object> requestContext = ((BindingProvider) smlPort).getRequestContext(); - requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, smlUrl.toString()); + requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, urlParticipantIdentifier.toString()); configureFaultHandling(requestContext); configureProxy(httpConduit); @@ -115,9 +124,16 @@ public class SmlClientFactory { IManageServiceMetadataWS smlPort = smlService.getManageServiceMetadataServicePort(); Client client = ClientProxy.getClient(smlPort); + URL urlSMPManagment; + try { + urlSMPManagment = new URL(smlUrl.getProtocol(), smlUrl.getHost(), smlUrl.getPort(), smlUrl.getFile() + "/manageservicemetadata", null); + } catch (MalformedURLException e) { + throw new IllegalStateException("Could not create participant URL: " + smlUrl.toString(), e); + } + HTTPConduit httpConduit = (HTTPConduit) client.getConduit(); Map<String, Object> requestContext = ((BindingProvider) smlPort).getRequestContext(); - requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, smlUrl.toString()); + requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, urlSMPManagment.toString()); configureFaultHandling(requestContext); configureProxy(httpConduit); diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/sml/SmlConnector.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/sml/SmlConnector.java index 604da7bfc..e82629674 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/sml/SmlConnector.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/sml/SmlConnector.java @@ -49,6 +49,12 @@ public class SmlConnector implements ApplicationContextAware { @Value("${bdmsl.integration.enabled:false}") private boolean smlIntegrationEnabled; + @Value("${bdmsl.integration.logical.address:}") + private String smpLogicalAddress; + + @Value("${bdmsl.integration.physical.address:0.0.0.0}") + private String smpPhysicalAddress; + private ApplicationContext ctx; public boolean registerInDns(ParticipantIdentifierType normalizedParticipantId, DBDomain domain) { @@ -76,7 +82,8 @@ public class SmlConnector implements ApplicationContextAware { try { ServiceMetadataPublisherServiceType smlSmpRequest = new ServiceMetadataPublisherServiceType(); smlSmpRequest.setPublisherEndpoint(new PublisherEndpointType()); - + smlSmpRequest.getPublisherEndpoint().setLogicalAddress(smpLogicalAddress); + smlSmpRequest.getPublisherEndpoint().setPhysicalAddress(smpPhysicalAddress); smlSmpRequest.setServiceMetadataPublisherID(domain.getSmlSmpId()); getSMPManagerClient(domain).create(smlSmpRequest); return true; @@ -99,13 +106,14 @@ public class SmlConnector implements ApplicationContextAware { } } - public void unregisterDomain(DBDomain domain) { + public boolean unregisterDomain(DBDomain domain) { if (!smlIntegrationEnabled) { - return; + return true; } log.info("Removing SMP id (Domain) from BDMSL: {} ", domain.getDomainCode()); try { getSMPManagerClient(domain).delete(domain.getSmlSmpId()); + return true; } catch (Exception e) { throw new SMPRuntimeException(ErrorCode.SML_INTEGRATION_EXCEPTION,e, ExceptionUtils.getRootCauseMessage(e)); } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SMPPropertyEnum.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SMPPropertyEnum.java index 4652b317d..88cb3e08b 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SMPPropertyEnum.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SMPPropertyEnum.java @@ -11,6 +11,10 @@ public enum SMPPropertyEnum { CS_DOCUMENTS("identifiersBehaviour.caseSensitive.DocumentIdentifierSchemes","casesensitive-doc-scheme1|casesensitive-doc-scheme2","Specifies schemes of document identifiers that must be considered CASE-SENSITIVE."), SML_ENABLED("bdmsl.integration.enabled","false","BDMSL (SML) integration ON/OFF switch"), SML_URL("bdmsl.integration.url","http://localhost:8080/edelivery-sml/","BDMSL (SML) endpoint"), + + SML_LOGICAL_ADDRESS("bdmsl.integration.logical.address","http://localhost:8080/smp/","BDMSL (SML) endpoint"), + SML_PHYSICAL_ADDRESS("bdmsl.integration.physical.address","0.0.0.0","BDMSL (SML) endpoint"), + SML_PROXY_HOST("bdmsl.integration.proxy.server","","Proxy "), SML_PROXY_PORT("bdmsl.integration.proxy.port","","Proxy "), SML_PROXY_USER("bdmsl.integration.proxy.user","","Proxy "), 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 9f0beba3a..3c154d1c3 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 @@ -39,7 +39,7 @@ import static eu.europa.ec.edelivery.smp.testutil.TestConstants.*; CaseSensitivityNormalizer.class,SmlConnector.class,ServiceMetadataSigner.class, ServiceGroupService.class, DomainService.class, ServiceMetadataService.class, ServiceGroupDao.class,ServiceMetadataDao.class, DomainDao.class, UserDao.class,DBAssertion.class, - UIKeystoreService.class, ConversionTestConfig.class, SecurityUtilsServices.class}) + UIKeystoreService.class, ConversionTestConfig.class, SecurityUtilsServices.class, SMLIntegrationService.class}) @Sql(scripts = "classpath:cleanup-database.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, config = @SqlConfig (transactionMode = SqlConfig.TransactionMode.ISOLATED, transactionManager = "transactionManager", diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/DomainServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/DomainServiceIntegrationTest.java index 6fddbf144..bf7e37947 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/DomainServiceIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/DomainServiceIntegrationTest.java @@ -13,44 +13,71 @@ package eu.europa.ec.edelivery.smp.services; +import eu.europa.ec.bdmsl.ws.soap.BadRequestFault; +import eu.europa.ec.bdmsl.ws.soap.InternalErrorFault; +import eu.europa.ec.bdmsl.ws.soap.NotFoundFault; +import eu.europa.ec.bdmsl.ws.soap.UnauthorizedFault; +import eu.europa.ec.edelivery.smp.config.H2JPATestConfig; +import eu.europa.ec.edelivery.smp.config.SmlIntegrationConfiguration; import eu.europa.ec.edelivery.smp.data.model.DBDomain; +import eu.europa.ec.edelivery.smp.data.model.DBServiceGroupDomain; import eu.europa.ec.edelivery.smp.exceptions.ErrorCode; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; +import eu.europa.ec.edelivery.smp.sml.SmlConnector; import eu.europa.ec.edelivery.smp.testutil.TestConstants; import eu.europa.ec.edelivery.smp.testutil.TestDBUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; -import static eu.europa.ec.edelivery.smp.testutil.TestConstants.TEST_DOMAIN_CODE_1; -import static org.junit.Assert.assertEquals; +import javax.xml.ws.http.HTTPException; + +import static eu.europa.ec.edelivery.smp.testutil.TestConstants.*; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; /** - * Purpose of class is to test ServiceGroupService base methods + * Purpose of class is to test ServiceGroupService base methods * * @author Joze Rihtarsic * @since 4.1 */ +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = {SmlIntegrationConfiguration.class, + SmlConnector.class, DomainService.class, SMLIntegrationService.class, + H2JPATestConfig.class}) +@TestPropertySource(properties = {"bdmsl.integration.enabled=true"}) public class DomainServiceIntegrationTest extends AbstractServiceIntegrationTest { @Rule public ExpectedException expectedExeption = ExpectedException.none(); + @Autowired + SmlIntegrationConfiguration integrationMock; + + @Autowired protected DomainService testInstance; @Before @Transactional public void prepareDatabase() { + integrationMock.reset(); prepareDatabaseForSignleDomainEnv(); } - @Test - public void getDomainForBlankCodeForSingleDomain(){ + public void getDomainForBlankCodeForSingleDomain() { // given assertEquals(1, domainDao.getAllDomains().size()); @@ -65,9 +92,9 @@ public class DomainServiceIntegrationTest extends AbstractServiceIntegrationTest } @Test - public void getDomainForBlankCodeForMultipleDomain(){ + public void getDomainForBlankCodeForMultipleDomain() { // given - DBDomain testDomain02 =TestDBUtils.createDBDomain(TestConstants.TEST_DOMAIN_CODE_2); + DBDomain testDomain02 = TestDBUtils.createDBDomain(TEST_DOMAIN_CODE_2); domainDao.persistFlushDetach(testDomain02); assertEquals(2, domainDao.getAllDomains().size()); expectedExeption.expect(SMPRuntimeException.class); @@ -79,9 +106,151 @@ public class DomainServiceIntegrationTest extends AbstractServiceIntegrationTest } + @Test + public void registerDomainAndParticipantsOK() throws NotFoundFault, UnauthorizedFault, InternalErrorFault, BadRequestFault { + /* given (init database - check setup) + * Domain: TEST_DOMAIN_CODE_1 + * Users: USERNAME_1, USER_CERT_2 + * ServiceGroup1: TEST_SG_ID_1, TEST_SG_SCHEMA_1 + * - Domain: TEST_DOMAIN_CODE_1 + * - Owners: USERNAME_1, USER_CERT_2 + * - Metadata: + * - TEST_DOC_ID_1, TEST_DOC_SCHEMA_1 + * + * + * ServiceGroup2: TEST_SG_ID_2, TEST_SG_SCHEMA_2 + * - Domain: TEST_DOMAIN_CODE_1 + * - Owners: USERNAME_1 + * - Metadata: / + */ + DBDomain testDomain01 = domainDao.getDomainByCode(TestConstants.TEST_DOMAIN_CODE_1).get(); + DBServiceGroupDomain serviceGroupDomain = serviceGroupDao.findServiceGroupDomain( + TEST_SG_ID_1, TEST_SG_SCHEMA_1, TEST_DOMAIN_CODE_1).get(); + DBServiceGroupDomain serviceGroupDomain2 = serviceGroupDao + .findServiceGroupDomain(TEST_SG_ID_2, TEST_SG_SCHEMA_2, TEST_DOMAIN_CODE_1).get(); + assertFalse(testDomain01.isSmlRegistered()); + assertFalse(serviceGroupDomain.isSmlRegistered()); + assertFalse(serviceGroupDomain2.isSmlRegistered()); + + // when + testInstance.registerDomainAndParticipants(testDomain01); + + // then + serviceGroupDomain = serviceGroupDao.findServiceGroupDomain( + TEST_SG_ID_1, TEST_SG_SCHEMA_1, TEST_DOMAIN_CODE_1).get(); + serviceGroupDomain2 = serviceGroupDao + .findServiceGroupDomain(TEST_SG_ID_2, TEST_SG_SCHEMA_2, TEST_DOMAIN_CODE_1).get(); + assertTrue(testDomain01.isSmlRegistered()); + assertTrue(serviceGroupDomain.isSmlRegistered()); + assertTrue(serviceGroupDomain2.isSmlRegistered()); + + // one sml domain create and two participant create was called + assertEquals(1, integrationMock.getSmpManagerClientMocks().size()); + verify(integrationMock.getSmpManagerClientMocks().get(0)).create(any()); + Mockito.verifyNoMoreInteractions(integrationMock.getSmpManagerClientMocks().toArray()); + + assertEquals(2, integrationMock.getParticipantManagmentClientMocks().size()); + verify(integrationMock.getParticipantManagmentClientMocks().get(0)).create(any()); + verify(integrationMock.getParticipantManagmentClientMocks().get(1)).create(any()); + Mockito.verifyNoMoreInteractions(integrationMock.getParticipantManagmentClientMocks().toArray()); + + } + + @Test + public void registerDomainAndParticipantsFailed() throws NotFoundFault, UnauthorizedFault, InternalErrorFault, BadRequestFault { + + DBDomain testDomain01 = domainDao.getDomainByCode(TestConstants.TEST_DOMAIN_CODE_1).get(); + DBServiceGroupDomain serviceGroupDomain = serviceGroupDao.findServiceGroupDomain( + TEST_SG_ID_1, TEST_SG_SCHEMA_1, TEST_DOMAIN_CODE_1).get(); + DBServiceGroupDomain serviceGroupDomain2 = serviceGroupDao + .findServiceGroupDomain(TEST_SG_ID_2, TEST_SG_SCHEMA_2, TEST_DOMAIN_CODE_1).get(); + assertFalse(testDomain01.isSmlRegistered()); + assertFalse(serviceGroupDomain.isSmlRegistered()); + assertFalse(serviceGroupDomain2.isSmlRegistered()); + integrationMock.setThrowExceptionAfterParticipantCallCount(1); + + + // when + try { + testInstance.registerDomainAndParticipants(testDomain01); + fail("Testcase should throw an error with code 400"); + } catch (Exception ex) { + assertEquals(400, ((HTTPException) ExceptionUtils.getRootCause(ex)).getStatusCode()); + } + + + // then + serviceGroupDomain = serviceGroupDao.findServiceGroupDomain( + TEST_SG_ID_1, TEST_SG_SCHEMA_1, TEST_DOMAIN_CODE_1).get(); + serviceGroupDomain2 = serviceGroupDao + .findServiceGroupDomain(TEST_SG_ID_2, TEST_SG_SCHEMA_2, TEST_DOMAIN_CODE_1).get(); + assertTrue(testDomain01.isSmlRegistered()); + assertTrue(serviceGroupDomain.isSmlRegistered()); + assertFalse(serviceGroupDomain2.isSmlRegistered()); + + // one sml domain create and two participant create was called + assertEquals(1, integrationMock.getSmpManagerClientMocks().size()); + verify(integrationMock.getSmpManagerClientMocks().get(0)).create(any()); + Mockito.verifyNoMoreInteractions(integrationMock.getSmpManagerClientMocks().toArray()); + + // only first succeeded + assertEquals(1, integrationMock.getParticipantManagmentClientMocks().size()); + verify(integrationMock.getParticipantManagmentClientMocks().get(0)).create(any()); + Mockito.verifyNoMoreInteractions(integrationMock.getParticipantManagmentClientMocks().toArray()); + } + + @Test + @Transactional + public void unregisterDomainAndParticipantsFromSmlOK() throws NotFoundFault, UnauthorizedFault, InternalErrorFault, BadRequestFault { + /* given (init database - check setup) + * Domain: TEST_DOMAIN_CODE_1 + * Users: USERNAME_1, USER_CERT_2 + * ServiceGroup1: TEST_SG_ID_1, TEST_SG_SCHEMA_1 + * - Domain: TEST_DOMAIN_CODE_1 + * - Owners: USERNAME_1, USER_CERT_2 + * - Metadata: + * - TEST_DOC_ID_1, TEST_DOC_SCHEMA_1 + * + * + * ServiceGroup2: TEST_SG_ID_2, TEST_SG_SCHEMA_2 + * - Domain: TEST_DOMAIN_CODE_1 + * - Owners: USERNAME_1 + * - Metadata: / + */ + DBDomain testDomain01 = domainDao.getDomainByCode(TestConstants.TEST_DOMAIN_CODE_1).get(); + DBServiceGroupDomain serviceGroupDomain = serviceGroupDao.findServiceGroupDomain( + TEST_SG_ID_1, TEST_SG_SCHEMA_1, TEST_DOMAIN_CODE_1).get(); + DBServiceGroupDomain serviceGroupDomain2 = serviceGroupDao + .findServiceGroupDomain(TEST_SG_ID_2, TEST_SG_SCHEMA_2, TEST_DOMAIN_CODE_1).get(); + testDomain01.setSmlRegistered(true); + serviceGroupDomain.setSmlRegistered(true); + serviceGroupDomain2.setSmlRegistered(true); + serviceGroupDao.updateServiceGroupDomain(serviceGroupDomain); + serviceGroupDao.updateServiceGroupDomain(serviceGroupDomain2); + // when + testInstance.unregisterDomainAndParticipantsFromSml(testDomain01); + // then + serviceGroupDomain = serviceGroupDao.findServiceGroupDomain( + TEST_SG_ID_1, TEST_SG_SCHEMA_1, TEST_DOMAIN_CODE_1).get(); + serviceGroupDomain2 = serviceGroupDao + .findServiceGroupDomain(TEST_SG_ID_2, TEST_SG_SCHEMA_2, TEST_DOMAIN_CODE_1).get(); + assertFalse(testDomain01.isSmlRegistered()); + assertFalse(serviceGroupDomain.isSmlRegistered()); + assertFalse(serviceGroupDomain2.isSmlRegistered()); + // one sml domain create and two participant create was called + assertEquals(1, integrationMock.getSmpManagerClientMocks().size()); + verify(integrationMock.getSmpManagerClientMocks().get(0)).delete(testDomain01.getSmlSmpId()); + Mockito.verifyNoMoreInteractions(integrationMock.getSmpManagerClientMocks().toArray()); + + assertEquals(2, integrationMock.getParticipantManagmentClientMocks().size()); + verify(integrationMock.getParticipantManagmentClientMocks().get(0)).delete(any()); + verify(integrationMock.getParticipantManagmentClientMocks().get(1)).delete(any()); + Mockito.verifyNoMoreInteractions(integrationMock.getParticipantManagmentClientMocks().toArray()); + + } } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/smlintegration/SmlClientFactoryAuthenticationByClientCertFromKeystoreTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/smlintegration/SmlClientFactoryAuthenticationByClientCertFromKeystoreTest.java index d6e81b2b7..32f29d546 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/smlintegration/SmlClientFactoryAuthenticationByClientCertFromKeystoreTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/smlintegration/SmlClientFactoryAuthenticationByClientCertFromKeystoreTest.java @@ -84,9 +84,11 @@ public class SmlClientFactoryAuthenticationByClientCertFromKeystoreTest { X509Certificate clientCert = getClientCertFromKeystore(cxfClient); assertEquals("C=EU,O=CEF Digit,OU=SMP,CN=Second domain", clientCert.getSubjectDN().getName()); - assertEquals("https://sml.url.pl", requestContext.get(Message.ENDPOINT_ADDRESS)); + assertEquals("https://sml.url.pl/manageparticipantidentifier", requestContext.get(Message.ENDPOINT_ADDRESS)); } + + @Test public void factoryProducesPreconfiguredCxfSMPClientThatAuthenticatesItselfWithGivenCertAlias() { //when @@ -99,7 +101,7 @@ public class SmlClientFactoryAuthenticationByClientCertFromKeystoreTest { X509Certificate clientCert = getClientCertFromKeystore(cxfClient); assertEquals("C=EU,O=CEF Digit,OU=SMP,CN=Second domain", clientCert.getSubjectDN().getName()); - assertEquals("https://sml.url.pl", requestContext.get(Message.ENDPOINT_ADDRESS)); + assertEquals("https://sml.url.pl/manageservicemetadata", requestContext.get(Message.ENDPOINT_ADDRESS)); } @Test diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/smlintegration/SmlClientFactoryAuthenticationByClientCertHttpHeaderTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/smlintegration/SmlClientFactoryAuthenticationByClientCertHttpHeaderTest.java index 38e445977..c1301b40a 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/smlintegration/SmlClientFactoryAuthenticationByClientCertHttpHeaderTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/smlintegration/SmlClientFactoryAuthenticationByClientCertHttpHeaderTest.java @@ -14,6 +14,7 @@ package eu.europa.ec.edelivery.smp.smlintegration; import eu.europa.ec.bdmsl.ws.soap.IManageParticipantIdentifierWS; +import eu.europa.ec.bdmsl.ws.soap.IManageServiceMetadataWS; import eu.europa.ec.edelivery.smp.sml.SmlClientFactory; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; @@ -71,7 +72,23 @@ public class SmlClientFactoryAuthenticationByClientCertHttpHeaderTest { List clientCerts = (List) httpHeaders.get("Client-Cert"); assertEquals(1, clientCerts.size()); assertEquals(CLIENT_CERT_HTTP_HEADER, clientCerts.get(0)); - assertEquals("https://sml.url.pl", requestContext.get(Message.ENDPOINT_ADDRESS)); + assertEquals("https://sml.url.pl/manageparticipantidentifier", requestContext.get(Message.ENDPOINT_ADDRESS)); + } + + @Test + public void factoryProducesPreconfiguredCxfCSMPlientThatAuthenticatesItselfWithGivenHttpHeader() { + //when + IManageServiceMetadataWS client = smlClientFactory.createSmp(null, CLIENT_CERT_HTTP_HEADER); + + //then + assertNotNull(client); + Client cxfClient = ClientProxy.getClient(client); + Map<String, Object> requestContext = cxfClient.getRequestContext(); + Map httpHeaders = (Map) requestContext.get(Message.PROTOCOL_HEADERS); + List clientCerts = (List) httpHeaders.get("Client-Cert"); + assertEquals(1, clientCerts.size()); + assertEquals(CLIENT_CERT_HTTP_HEADER, clientCerts.get(0)); + assertEquals("https://sml.url.pl/manageservicemetadata", requestContext.get(Message.ENDPOINT_ADDRESS)); } } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/PropertiesConfig.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/PropertiesConfig.java index 361d286aa..a7d8dc5cf 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/PropertiesConfig.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/PropertiesConfig.java @@ -13,13 +13,14 @@ package eu.europa.ec.edelivery.smp.config; -import eu.europa.ec.edelivery.smp.utils.SMPPropertyEnum; import eu.europa.ec.edelivery.smp.data.model.DBConfiguration; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; +import eu.europa.ec.edelivery.smp.logging.SMPLogger; +import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.SecurityUtilsServices; +import eu.europa.ec.edelivery.smp.utils.SMPPropertyEnum; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.*; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.jdbc.datasource.DriverManagerDataSource; @@ -56,10 +57,17 @@ import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.INTERNAL_ERROR; "eu.europa.ec"}) @PropertySources({ @PropertySource(value = "classpath:config.properties", ignoreResourceNotFound = true), - @PropertySource(value = "classpath:smp.config.properties", ignoreResourceNotFound = true) + @PropertySource(value = "classpath:smp.config.properties", ignoreResourceNotFound = true), + @PropertySource(value = "classpath:application.properties", ignoreResourceNotFound = true) }) public class PropertiesConfig { + private static final String PROP_BUILD_NAME="smp.artifact.name"; + private static final String PROP_BUILD_VERSION="smp.artifact.version"; + private static final String PROP_BUILD_TIME="smp.artifact.build.time"; + + SMPLogger LOG = SMPLoggerFactory.getLogger(PropertiesConfig.class); + // create own instance because at this time SecurityUtilsServices is not ready to instantiate SecurityUtilsServices securityUtilsServices = new SecurityUtilsServices(); @@ -68,11 +76,32 @@ public class PropertiesConfig { PropertySourcesPlaceholderConfigurer propertiesConfig = new PropertySourcesPlaceholderConfigurer(); Properties prop = getDatabaseProperties(); + logBuildProperties(); + propertiesConfig.setProperties(prop); propertiesConfig.setLocalOverride(true); return propertiesConfig; } + private void logBuildProperties(){ + InputStream is = PropertiesConfig.class.getResourceAsStream("/application.properties"); + if(is!=null){ + Properties applProp = new Properties(); + try { + applProp.load(is); + + LOG.info("Start application: name: {}, version: {}, build time: {}.",applProp.getProperty(PROP_BUILD_NAME) + ,applProp.getProperty(PROP_BUILD_VERSION) + ,applProp.getProperty(PROP_BUILD_TIME)); + } catch (IOException e) { + LOG.error( "Error occurred while reading application properties. Is file /application.properties included in war!", e); + } + } else { + LOG.error( "Not found application build properties: /application.properties!"); + } + + } + private Properties getDatabaseProperties() { Properties fileProperties = getFileProperties(); @@ -108,7 +137,7 @@ public class PropertiesConfig { */ protected void initializeProperties(EntityManager em, Properties fileProperties, Properties initProperties) { em.getTransaction().begin(); - + LOG.info( "Database configuration table is empty! initialize new values from property file!"); initNewValues(em, fileProperties, initProperties); for (SMPPropertyEnum val : SMPPropertyEnum.values()) { DBConfiguration dbConf = null; @@ -160,6 +189,7 @@ public class PropertiesConfig { protected void initNewValues(EntityManager em, Properties fileProperties, Properties initProperties) { File settingsFolder = calculateSettingsPath(fileProperties); + LOG.info( "Generate new keystore to folder: " + settingsFolder.getAbsolutePath()); // add configuration path storeDBEntry(em, SMPPropertyEnum.CONFIGURATION_DIR, settingsFolder.getPath()); @@ -169,7 +199,9 @@ public class PropertiesConfig { // store encryption filename + File fEncryption = new File(settingsFolder, SMPPropertyEnum.ENCRYPTION_FILENAME.getDefValue()); + LOG.info( "Generate new encryption key: " + fEncryption.getName()); securityUtilsServices.generatePrivateSymmetricKey(fEncryption); storeDBEntry(em, SMPPropertyEnum.ENCRYPTION_FILENAME, fEncryption.getName()); initProperties.setProperty(SMPPropertyEnum.ENCRYPTION_FILENAME.getProperty(), fEncryption.getName()); @@ -194,6 +226,7 @@ public class PropertiesConfig { newKeystore.load(null, newKeyPassword.toCharArray()); // merge keys from signature keystore if (!StringUtils.isBlank(sigKeystorePath)) { + LOG.info( "Import keys from keystore for signature: " + sigKeystorePath); String keypasswd = fileProperties.getProperty(SMPPropertyEnum.SIGNATURE_KEYSTORE_PASSWORD.getProperty()); try (FileInputStream fis = new FileInputStream(sigKeystorePath)) { KeyStore sourceKeystore = KeyStore.getInstance(KeyStore.getDefaultType()); @@ -204,6 +237,7 @@ public class PropertiesConfig { // merge keys from integration keystore if (!StringUtils.isBlank(smlKeystorePath) && !StringUtils.equalsIgnoreCase(smlKeystorePath, sigKeystorePath)) { + LOG.info( "Import keys from keystore for sml integration: " + smlKeystorePath); String keypasswd = fileProperties.getProperty(SMPPropertyEnum.SML_KEYSTORE_PASSWORD.getProperty()); try (FileInputStream fis = new FileInputStream(smlKeystorePath)) { KeyStore sourceKeystore = KeyStore.getInstance(KeyStore.getDefaultType()); @@ -251,13 +285,14 @@ public class PropertiesConfig { * @return */ private DataSource getDatasource(Properties connectionProp) { - + LOG.info( "Start database properties"); DataSource datasource = null; String url = connectionProp.getProperty("jdbc.url"); String jndiDatasourceName = connectionProp.getProperty("datasource.jndi"); jndiDatasourceName = StringUtils.isBlank(jndiDatasourceName) ? "jdbc/smpDatasource" : jndiDatasourceName; - if (url != null) { + if (!StringUtils.isBlank(url)) { + LOG.info( "Connect to {}.", url); DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(); driverManagerDataSource.setDriverClassName(connectionProp.getProperty("jdbc.driver")); driverManagerDataSource.setUrl(url); @@ -265,12 +300,14 @@ public class PropertiesConfig { driverManagerDataSource.setPassword(connectionProp.getProperty("jdbc.password")); datasource = driverManagerDataSource; } else { + LOG.info( "Use JNDI {} to connect to database.", jndiDatasourceName); JndiObjectFactoryBean dataSource = new JndiObjectFactoryBean(); dataSource.setJndiName(jndiDatasourceName); try { dataSource.afterPropertiesSet(); } catch (IllegalArgumentException | NamingException e) { // rethrow + LOG.error( "Error occurred while retriving datasource whith JNDI {}. Is datasource configured in server!", jndiDatasourceName); throw new SMPRuntimeException(INTERNAL_ERROR, e, "Error occurred while retrieving datasource: " + jndiDatasourceName, e.getMessage()); } datasource = (DataSource) dataSource.getObject(); @@ -279,14 +316,17 @@ public class PropertiesConfig { } protected Properties getFileProperties() { + LOG.info( "Start read file properties from '/smp.config.properties'"); InputStream is = PropertiesConfig.class.getResourceAsStream("/smp.config.properties"); if (is == null) { + LOG.info( "File '/smp.config.properties' not found in classpath, read '/config.properties'"); is = PropertiesConfig.class.getResourceAsStream("/config.properties"); } Properties connectionProp = new Properties(); try { connectionProp.load(is); } catch (IOException e) { + LOG.error( "IOException occurred while reading properties", e); throw new SMPRuntimeException(INTERNAL_ERROR, e, "Error occurred while reading properties.", e.getMessage()); } return connectionProp; @@ -312,7 +352,7 @@ public class PropertiesConfig { } private static class DatabaseProperties extends Properties { - + SMPLogger LOG = SMPLoggerFactory.getLogger(PropertiesConfig.class); private static final long serialVersionUID = 1L; public DatabaseProperties(EntityManager em) { @@ -321,6 +361,9 @@ public class PropertiesConfig { List<DBConfiguration> lst = tq.getResultList(); for (DBConfiguration dc : lst) { if(dc.getValue()!=null) { + + LOG.info("Set property: '{}' value: '{}'",dc.getProperty(), + dc.getProperty().toLowerCase().contains("password")?"******": dc.getValue()); setProperty(dc.getProperty(), dc.getValue()); } } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ApplicationResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ApplicationResource.java index 8ad2afa91..0d79da20d 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ApplicationResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ApplicationResource.java @@ -30,12 +30,15 @@ public class ApplicationResource { @Autowired private Environment env; - @Value("${Artifact-Name}") - private String artifactName; - @Value("${Artifact-Version}") - private String artifactVersion; - @Value("${Build-Time}") - private String buildTime; + @Value("${smp.artifact.name:eDelivery SMP}") + String artifactName; + @Value("${smp.artifact.version:}") + String artifactVersion; + @Value("${smp.artifact.build.time:}") + String buildTime; + + @Value("${bdmsl.integration.enabled}") + boolean smlIntegrationEnabled; @RequestMapping(method = RequestMethod.GET, path = "name") @@ -49,7 +52,16 @@ public class ApplicationResource { } @RequestMapping(method = RequestMethod.GET, path = "info") - public SmpInfoRO getDisplayVersion() { + public SmpInfoRO getApplicationInfo() { + SmpInfoRO info = new SmpInfoRO(); + info.setVersion(getDisplayVersion()); + info.setSmlIntegrationOn(smlIntegrationEnabled); + info.setContextPath(getRootContext()); + return info; + } + + + public String getDisplayVersion() { StringBuilder display = new StringBuilder(); display.append(artifactName); display.append(" Version ["); @@ -57,12 +69,6 @@ public class ApplicationResource { display.append("] Build-Time ["); display.append(buildTime + "|" + TimeZone.getDefault().getDisplayName()); display.append("]"); - - SmpInfoRO info = new SmpInfoRO(); - info.setVersion(display.toString()); - return info; + return display.toString(); } - - - } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/DomainResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/DomainResource.java index e94afe48d..848123274 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/DomainResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/DomainResource.java @@ -3,22 +3,34 @@ package eu.europa.ec.edelivery.smp.ui; import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationToken; import eu.europa.ec.edelivery.smp.auth.SMPAuthority; +import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.data.model.DBUser; import eu.europa.ec.edelivery.smp.data.ui.DeleteEntityValidation; import eu.europa.ec.edelivery.smp.data.ui.DomainRO; +import eu.europa.ec.edelivery.smp.data.ui.KeystoreImportResult; import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; +import eu.europa.ec.edelivery.smp.services.DomainService; import eu.europa.ec.edelivery.smp.services.ui.UIDomainService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import javax.annotation.PostConstruct; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; import java.util.Arrays; import java.util.List; +import java.util.Optional; /** * @author Joze Rihtarsic @@ -34,6 +46,9 @@ public class DomainResource { @Autowired private UIDomainService uiDomainService; + @Autowired + private DomainService domainService; + @PostConstruct protected void init() { @@ -69,4 +84,27 @@ public class DomainResource { dres.getListIds().addAll(query); return uiDomainService.validateDeleteRequest(dres); } + + @PostMapping(value = "/{id}/smlregister/{domaincode}") + @PreAuthorize("@smpAuthorizationService.systemAdministrator || @smpAuthorizationService.isCurrentlyLoggedIn(#id)") + public void registerDomain(@PathVariable("id") Long id, + @PathVariable("domaincode") String domaincode + ) { + LOG.info("SML register domain code: {}, user id {}", domaincode, id); + // try to open keystore + DBDomain dbDomain = domainService.getDomain(domaincode); + domainService.registerDomainAndParticipants(dbDomain); + } + + + @PostMapping(value = "/{id}/smlunregister/{domaincode}") + @PreAuthorize("@smpAuthorizationService.systemAdministrator || @smpAuthorizationService.isCurrentlyLoggedIn(#id)") + public void unregisterDomainAndParticiants(@PathVariable("id") Long id, + @PathVariable("domaincode") String domaincode + ) { + LOG.info("SML unregister domain code: {}, user id {}", domaincode, id); + // try to open keystore + DBDomain dbDomain = domainService.getDomain(domaincode); + domainService.unregisterDomainAndParticipantsFromSml(dbDomain); + } } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/KeystoreResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/KeystoreResource.java index 69d0ca212..b04798e15 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/KeystoreResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/KeystoreResource.java @@ -96,7 +96,7 @@ public class KeystoreResource { @DeleteMapping(value = "/{id}/delete/{alias}", produces = {"application/json"}) @PreAuthorize("@smpAuthorizationService.systemAdministrator || @smpAuthorizationService.isCurrentlyLoggedIn(#id)") - public KeystoreImportResult uploadKeystore(@PathVariable("id") Long id, + public KeystoreImportResult deleteCertificate(@PathVariable("id") Long id, @PathVariable("alias") String alias) { LOG.info("Remove alias by user id {}, alias {}.", id, alias); KeystoreImportResult keystoreImportResult = new KeystoreImportResult(); diff --git a/smp-webapp/src/main/resources/application.properties b/smp-webapp/src/main/resources/application.properties new file mode 100644 index 000000000..61b502b9d --- /dev/null +++ b/smp-webapp/src/main/resources/application.properties @@ -0,0 +1,3 @@ +smp.artifact.name=eDelivery SMP +smp.artifact.version=${project.version} +smp.artifact.build.time=${buildtimestamp} \ No newline at end of file diff --git a/smp-webapp/src/main/resources/config.properties b/smp-webapp/src/main/resources/config.properties index 544058456..d0ec01682 100644 --- a/smp-webapp/src/main/resources/config.properties +++ b/smp-webapp/src/main/resources/config.properties @@ -16,10 +16,6 @@ # Authentication with Blue Coat means that all HTTP requests having 'Client-Cert' header will be authenticated # as username placed in the header. # Never expose SMP to the WEB without properly configured reverse-proxy and active blue coat. -Artifact-Name= eDelivery SMP -Artifact-Version= 4.1.0-SNAPSHOT -Build-Time= 22/10/2018 - authentication.blueCoat.enabled=false ## Only set to false in PRODUCTION mode. This variable is used to clear the context path of the SMP diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/config/PropertiesTestConfig.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/config/PropertiesTestConfig.java index f3164d344..0b7319c94 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/config/PropertiesTestConfig.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/config/PropertiesTestConfig.java @@ -13,7 +13,10 @@ package eu.europa.ec.edelivery.smp.config; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.PropertySources; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import java.nio.file.Path; @@ -25,7 +28,8 @@ import java.util.Properties; */ @Configuration @PropertySources({ - @PropertySource(value = "classpath:config.properties", ignoreResourceNotFound = true) + @PropertySource(value = "classpath:config.properties", ignoreResourceNotFound = true), + @PropertySource(value = "classpath:application.properties", ignoreResourceNotFound = true) }) public class PropertiesTestConfig { @@ -33,7 +37,7 @@ public class PropertiesTestConfig { @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { - Path resourceDirectory = Paths.get("src", "test", "resources", "keystores"); + Path resourceDirectory = Paths.get("src", "test", "resources", "keystores"); String path = resourceDirectory.toFile().getAbsolutePath(); PropertySourcesPlaceholderConfigurer propertiesConfig = new PropertySourcesPlaceholderConfigurer(); @@ -41,16 +45,16 @@ public class PropertiesTestConfig { Properties localProps = new Properties(); localProps.setProperty("jdbc.driverClassName", "org.h2.Driver"); localProps.setProperty("jdbc.url", "jdbc:h2:file:./target/myDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=TRUE;AUTO_SERVER=TRUE"); - localProps.setProperty( "jdbc.user", "smp"); - localProps.setProperty( "jdbc.pass", "smp"); - localProps.setProperty( "spring.jpa.properties.hibernate.dialect", "org.hibernate.dialect.H2Dialect"); - localProps.setProperty( "spring.jpa.generate-ddl", "true"); - localProps.setProperty( "spring.jpa.properties.hibernate.hbm2ddl.auto", "create"); + localProps.setProperty("jdbc.user", "smp"); + localProps.setProperty("jdbc.pass", "smp"); + localProps.setProperty("spring.jpa.properties.hibernate.dialect", "org.hibernate.dialect.H2Dialect"); + localProps.setProperty("spring.jpa.generate-ddl", "true"); + localProps.setProperty("spring.jpa.properties.hibernate.hbm2ddl.auto", "create"); localProps.setProperty("configuration.dir", path); - localProps.setProperty( "encryption.key.filename","encryptionKey.key"); - localProps.setProperty( "smp.keystore.password", "FarFJE2WUfY39SVRTFOqSg=="); - localProps.setProperty( "smp.keystore.filename", "smp-keystore_multiple_domains.jks"); + localProps.setProperty("encryption.key.filename", "encryptionKey.key"); + localProps.setProperty("smp.keystore.password", "FarFJE2WUfY39SVRTFOqSg=="); + localProps.setProperty("smp.keystore.filename", "smp-keystore_multiple_domains.jks"); propertiesConfig.setProperties(localProps); propertiesConfig.setLocalOverride(true); diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/ApplicationResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/ApplicationResourceTest.java index e6f2449a9..0586aa7cf 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/ApplicationResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/ApplicationResourceTest.java @@ -1,9 +1,11 @@ package eu.europa.ec.edelivery.smp.ui; +import com.fasterxml.jackson.databind.ObjectMapper; import eu.europa.ec.edelivery.smp.config.PropertiesTestConfig; import eu.europa.ec.edelivery.smp.config.SmpAppConfig; import eu.europa.ec.edelivery.smp.config.SmpWebAppConfig; import eu.europa.ec.edelivery.smp.config.SpringSecurityConfig; +import eu.europa.ec.edelivery.smp.data.ui.SmpInfoRO; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -11,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mock.web.MockServletContext; import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -24,10 +27,9 @@ import org.springframework.web.context.WebApplicationContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -41,14 +43,25 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @Sql("classpath:/cleanup-database.sql") @Sql("classpath:/webapp_integration_test_data.sql") @SqlConfig(encoding = "UTF-8") +@TestPropertySource(properties = { + "smp.artifact.name=TestApplicationSmpName", + "smp.artifact.version=TestApplicationVersion", + "smp.artifact.build.time=2018-11-27 00:00:00", + "bdmsl.integration.enabled=true"}) + public class ApplicationResourceTest { - private static final String PATH="/ui/rest/application"; + private static final String PATH = "/ui/rest/application"; @Autowired private WebApplicationContext webAppContext; + @Autowired + private ApplicationResource applicationResource; + + private MockMvc mvc; private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("smp_admin", "test123"); + @Before public void setup() { mvc = MockMvcBuilders.webAppContextSetup(webAppContext) @@ -56,7 +69,6 @@ public class ApplicationResourceTest { .build(); - initServletContext(); } @@ -74,9 +86,10 @@ public class ApplicationResourceTest { .getResponse() .getContentAsString(); - assertEquals("eDelivery SMP", value); + assertEquals("TestApplicationSmpName", value); } + @Test public void getRootContext() throws Exception { String value = mvc.perform(get(PATH + "/rootContext")) @@ -89,13 +102,24 @@ public class ApplicationResourceTest { } @Test - public void getDisplayVersion() throws Exception { + public void getDisplayName() throws Exception { + String value = applicationResource.getDisplayVersion(); + assertEquals("TestApplicationSmpName Version [TestApplicationVersion] Build-Time [2018-11-27 00:00:00|Central European Time]", value); + } + + @Test + public void getApplicationInfoTest() throws Exception { String value = mvc.perform(get(PATH + "/info")) .andExpect(status().isOk()) .andReturn() .getResponse() .getContentAsString(); + ObjectMapper mapper = new ObjectMapper(); + SmpInfoRO info = mapper.readValue(value, SmpInfoRO.class); - assertEquals("{\"version\":\"eDelivery SMP Version [4.1.0-SNAPSHOT] Build-Time [22/10/2018|Central European Time]\"}", value); + assertEquals("TestApplicationSmpName Version [TestApplicationVersion] Build-Time [2018-11-27 00:00:00|Central European Time]", info.getVersion()); + assertEquals(true, info.isSmlIntegrationOn()); + assertEquals("/", info.getContextPath()); } + } \ No newline at end of file diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/KeystoreResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/KeystoreResourceTest.java new file mode 100644 index 000000000..8e5bdc2da --- /dev/null +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/KeystoreResourceTest.java @@ -0,0 +1,91 @@ +package eu.europa.ec.edelivery.smp.ui; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.europa.ec.edelivery.smp.config.PropertiesTestConfig; +import eu.europa.ec.edelivery.smp.config.SmpAppConfig; +import eu.europa.ec.edelivery.smp.config.SmpWebAppConfig; +import eu.europa.ec.edelivery.smp.config.SpringSecurityConfig; +import eu.europa.ec.edelivery.smp.data.ui.SmpInfoRO; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockServletContext; +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.jdbc.SqlConfig; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.RequestPostProcessor; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.ContextLoaderListener; +import org.springframework.web.context.WebApplicationContext; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import static org.junit.Assert.assertEquals; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { + PropertiesTestConfig.class, + SmpAppConfig.class, + SmpWebAppConfig.class, + SpringSecurityConfig.class}) +@WebAppConfiguration +@Sql("classpath:/cleanup-database.sql") +@Sql("classpath:/webapp_integration_test_data.sql") +@SqlConfig(encoding = "UTF-8") +@TestPropertySource(properties = { + "smp.artifact.name=TestApplicationSmpName", + "smp.artifact.version=TestApplicationVersion", + "smp.artifact.build.time=2018-11-27 00:00:00", + "bdmsl.integration.enabled=true"}) + +public class KeystoreResourceTest { + private static final String PATH = "/ui/rest/application"; + + @Autowired + private WebApplicationContext webAppContext; + + + + + private MockMvc mvc; + private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("smp_admin", "test123"); + + @Before + public void setup() { + mvc = MockMvcBuilders.webAppContextSetup(webAppContext) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build(); + + + initServletContext(); + } + + private void initServletContext() { + MockServletContext sc = new MockServletContext(""); + ServletContextListener listener = new ContextLoaderListener(webAppContext); + ServletContextEvent event = new ServletContextEvent(sc); + } + + @Test + public void getKeyCertificateList() { + } + + @Test + public void uploadKeystore() { + } + + + +} \ No newline at end of file -- GitLab