From bb066846c89ab2c7128ed43748a5b32ebfba9729 Mon Sep 17 00:00:00 2001 From: Joze RIHTARSIC <joze.rihtarsic@ext.ec.europa.eu> Date: Wed, 18 Jul 2018 13:25:31 +0200 Subject: [PATCH] Add new exception InvalidOwner was added for update servicegroup with invalid owner. --- .../smp/exceptions/InvalidOwnerException.java | 28 ++++++ .../smp/services/ServiceGroupService.java | 28 +++++- ...actServiceGroupServiceIntegrationTest.java | 4 +- ...ServiceMultipleDomainsIntegrationTest.java | 4 +- ...oupServiceSingleDomainIntegrationTest.java | 87 ++++++++++++++++++- .../ServiceMetadataIntegrationTest.java | 2 +- .../controllers/ServiceGroupController.java | 11 +-- 7 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/InvalidOwnerException.java diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/InvalidOwnerException.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/InvalidOwnerException.java new file mode 100644 index 000000000..403e68df5 --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/InvalidOwnerException.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 European Commission | CEF eDelivery + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence attached in file: LICENCE-EUPL-v1.2.pdf + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and limitations under the Licence. + */ + +package eu.europa.ec.edelivery.smp.exceptions; + +/** + * This exceptions is thrown if the provided user name does not exist. + */ +public class InvalidOwnerException extends RuntimeException { + + public InvalidOwnerException(String username) { + this(username, null); + } + public InvalidOwnerException(String username, String message) { + super("Invalid owner '" + username + "'. " + message!=null?message:"" ); + } + +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ServiceGroupService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ServiceGroupService.java index 6979334dd..a58f84611 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ServiceGroupService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ServiceGroupService.java @@ -19,6 +19,7 @@ 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.dao.UserDao; import eu.europa.ec.edelivery.smp.data.model.*; +import eu.europa.ec.edelivery.smp.exceptions.InvalidOwnerException; import eu.europa.ec.edelivery.smp.exceptions.NotFoundException; import eu.europa.ec.edelivery.smp.exceptions.UnknownUserException; import eu.europa.ec.edelivery.smp.exceptions.WrongInputFieldException; @@ -28,16 +29,20 @@ import org.oasis_open.docs.bdxr.ns.smp._2016._05.ServiceGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.UnsupportedEncodingException; import java.util.HashSet; import java.util.Optional; +import java.util.Set; import java.util.regex.Pattern; import static eu.europa.ec.edelivery.smp.conversion.ServiceGroupConverter.toDbModel; import static eu.europa.ec.smp.api.Identifiers.asString; import static java.lang.String.format; +import static java.net.URLDecoder.decode; import static java.util.Arrays.asList; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -48,6 +53,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; public class ServiceGroupService { private static final Pattern DOMAIN_ID_PATTERN = Pattern.compile("[a-zA-Z0-9]{1,50}"); + private static final String UTF_8 = "UTF-8"; + + private static final Logger LOG = LoggerFactory.getLogger(ServiceGroupService.class); @Autowired private CaseSensitivityNormalizer caseSensitivityNormalizer; @@ -76,9 +84,16 @@ public class ServiceGroupService { } @Transactional - public boolean saveServiceGroup(ServiceGroup serviceGroup, String domain, String newOwnerName) { + public boolean saveServiceGroup(ServiceGroup serviceGroup, String domain, String serviceGroupOwner, String authenticatedUser) { ServiceGroup normalizedServiceGroup = normalizeIdentifierCaseSensitivity(serviceGroup); ParticipantIdentifierType normalizedParticipantId = normalizedServiceGroup.getParticipantIdentifier(); + String newOwnerName; + try { + newOwnerName = isNotBlank(serviceGroupOwner) ? decode(serviceGroupOwner, UTF_8) : authenticatedUser; + } catch (UnsupportedEncodingException | IllegalArgumentException ex) { + throw new InvalidOwnerException(serviceGroupOwner, "Unsupported or invalid encoding: " + ex.getMessage()); + } + DBUser newOwner = userDao.find(newOwnerName); if (newOwner == null) { @@ -87,10 +102,21 @@ public class ServiceGroupService { DBServiceGroup dbServiceGroup = serviceGroupDao.find(toDbModel(normalizedParticipantId)); + validateDomain(dbServiceGroup, domain); String extensions = ServiceGroupConverter.extractExtensionsPayload(normalizedServiceGroup); if (dbServiceGroup != null) { + // test service owner + Set<DBOwnership> owSet = dbServiceGroup.getOwnerships(); + Optional<DBOwnership> owner = owSet.stream().filter(dbOwnership -> dbOwnership.getUser().getUsername().equals(newOwnerName)).findFirst(); + // test serviceGroupOwner but use newOwnerName - because it is decoded + if (serviceGroupOwner!=null && !owner.isPresent()){ + String msg = "User: " +newOwnerName+ " is not owner of service group: " +dbServiceGroup.getId().getBusinessIdentifierScheme() + "::" + dbServiceGroup.getId().getBusinessIdentifier(); + LOG.error(msg); + throw new InvalidOwnerException(serviceGroupOwner, msg); + } + dbServiceGroup.setExtension(extensions); serviceGroupDao.persistFlushDetach(dbServiceGroup); return false; diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceGroupServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceGroupServiceIntegrationTest.java index 8421429fc..c0f666543 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceGroupServiceIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceGroupServiceIntegrationTest.java @@ -46,6 +46,8 @@ abstract class AbstractServiceGroupServiceIntegrationTest { protected static final String SERVICE_GROUP_XML_PATH = "/eu/europa/ec/edelivery/smp/services/ServiceGroupPoland.xml"; protected static final ParticipantIdentifierType SERVICE_GROUP_ID = asParticipantId("participant-scheme-qns::urn:poland:ncpb"); public static final String ADMIN_USERNAME = "test_admin"; + public static final String CERT_USER="CN=comon name,O=org,C=BE:0000000000000066"; + public static final String CERT_USER_ENCODED="CN%3Dcomon%20name%2CO%3Dorg%2CC%3DBE%3A0000000000000066"; @PersistenceContext protected EntityManager em; @@ -61,7 +63,7 @@ abstract class AbstractServiceGroupServiceIntegrationTest { protected ServiceGroup saveServiceGroup() throws IOException { ServiceGroup inServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); - serviceGroupService.saveServiceGroup(inServiceGroup, null, ADMIN_USERNAME); + serviceGroupService.saveServiceGroup(inServiceGroup, null, ADMIN_USERNAME, ADMIN_USERNAME); return inServiceGroup; } } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceMultipleDomainsIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceMultipleDomainsIntegrationTest.java index 3a7bbf209..7f44fadcb 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceMultipleDomainsIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceMultipleDomainsIntegrationTest.java @@ -50,7 +50,7 @@ public class ServiceGroupServiceMultipleDomainsIntegrationTest extends AbstractS public void saveAndReadPositiveScenarioForMultipleDomain() throws IOException { // given ServiceGroup inServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); - serviceGroupService.saveServiceGroup(inServiceGroup, SECOND_DOMAIN_ID, ADMIN_USERNAME); + serviceGroupService.saveServiceGroup(inServiceGroup, SECOND_DOMAIN_ID, ADMIN_USERNAME, ADMIN_USERNAME); // when DBServiceGroup dbServiceGroup = serviceGroupDao.find(toDbModel(SERVICE_GROUP_ID)); @@ -71,7 +71,7 @@ public class ServiceGroupServiceMultipleDomainsIntegrationTest extends AbstractS ServiceGroup newServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); //when-then - serviceGroupService.saveServiceGroup(newServiceGroup, SECOND_DOMAIN_ID, ADMIN_USERNAME); + serviceGroupService.saveServiceGroup(newServiceGroup, SECOND_DOMAIN_ID, ADMIN_USERNAME, ADMIN_USERNAME); } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceSingleDomainIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceSingleDomainIntegrationTest.java index a265bce63..57f2c29bf 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceSingleDomainIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceSingleDomainIntegrationTest.java @@ -16,9 +16,14 @@ package eu.europa.ec.edelivery.smp.services; import eu.europa.ec.edelivery.smp.data.model.DBOwnership; import eu.europa.ec.edelivery.smp.data.model.DBOwnershipId; import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup; +import eu.europa.ec.edelivery.smp.exceptions.InvalidOwnerException; import eu.europa.ec.edelivery.smp.exceptions.NotFoundException; +import eu.europa.ec.edelivery.smp.exceptions.UnknownUserException; import eu.europa.ec.edelivery.smp.exceptions.WrongInputFieldException; +import org.hamcrest.core.StringStartsWith; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.oasis_open.docs.bdxr.ns.smp._2016._05.ExtensionType; import org.oasis_open.docs.bdxr.ns.smp._2016._05.ServiceGroup; import org.oasis_open.docs.bdxr.ns.smp._2016._05.ServiceMetadataReferenceType; @@ -27,6 +32,7 @@ import org.springframework.test.context.jdbc.Sql; import javax.xml.bind.JAXBException; import java.io.IOException; import java.util.List; +import java.util.regex.Matcher; import static eu.europa.ec.edelivery.smp.conversion.ServiceGroupConverter.toDbModel; import static eu.europa.ec.edelivery.smp.conversion.ServiceGroupConverter.unmarshal; @@ -41,6 +47,13 @@ import static org.junit.Assert.*; @Sql("classpath:/service_integration_test_data.sql") public class ServiceGroupServiceSingleDomainIntegrationTest extends AbstractServiceGroupServiceIntegrationTest { + private static String UnknownUser="UnknownUser"; + + + + @Rule + public ExpectedException expectedExeption = ExpectedException.none(); + @Test public void makeSureServiceGroupDoesNotExistAlready(){ DBServiceGroup dbServiceGroup = serviceGroupDao.find(toDbModel(SERVICE_GROUP_ID)); @@ -99,7 +112,7 @@ public class ServiceGroupServiceSingleDomainIntegrationTest extends AbstractServ newServiceGroup.getExtensions().add(newExtension); //when - serviceGroupService.saveServiceGroup(newServiceGroup, null, ADMIN_USERNAME); + serviceGroupService.saveServiceGroup(newServiceGroup, null, ADMIN_USERNAME, ADMIN_USERNAME); ServiceGroup resultServiceGroup = serviceGroupService.getServiceGroup(SERVICE_GROUP_ID); //then @@ -107,6 +120,72 @@ public class ServiceGroupServiceSingleDomainIntegrationTest extends AbstractServ assertEquals(marshall(newServiceGroup), marshall(resultServiceGroup)); } + @Test + public void updateUnknownUserException() throws IOException, JAXBException { + + String invalidServiceUser = "WrongOwner"; + //given + ServiceGroup oldServiceGroup = saveServiceGroup(); + expectedExeption.expect(UnknownUserException.class); + expectedExeption.expectMessage("Unknown user '"+invalidServiceUser+"'"); + + ServiceGroup newServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); + ExtensionType newExtension = new ExtensionType(); + newExtension.setExtensionID("new extension ID the second"); + newServiceGroup.getExtensions().add(newExtension); + + //when + serviceGroupService.saveServiceGroup(newServiceGroup, null, invalidServiceUser, ADMIN_USERNAME); + } + + @Test + public void updateInvalidUserException() throws IOException, JAXBException { + + //given + ServiceGroup oldServiceGroup = saveServiceGroup(); + expectedExeption.expect(InvalidOwnerException.class); + expectedExeption.expectMessage("User: "+CERT_USER+" is not owner of service group: participant-scheme-qns::urn:poland:ncpb"); + + ServiceGroup newServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); + + //when + serviceGroupService.saveServiceGroup(newServiceGroup, null, CERT_USER, ADMIN_USERNAME); + + } + + @Test + public void updateEncodedInvalidUserException() throws IOException, JAXBException { + + //given + ServiceGroup oldServiceGroup = saveServiceGroup(); + expectedExeption.expect(InvalidOwnerException.class); + expectedExeption.expectMessage("User: "+CERT_USER+" is not owner of service group: participant-scheme-qns::urn:poland:ncpb"); + + ServiceGroup newServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); + + //when + serviceGroupService.saveServiceGroup(newServiceGroup, null, CERT_USER_ENCODED, ADMIN_USERNAME); + + } + + @Test + public void updateInvalidUserEncodingException() throws IOException, JAXBException { + String username = "test::20%atest"; + //given + ServiceGroup oldServiceGroup = saveServiceGroup(); + expectedExeption.expect(InvalidOwnerException.class); + expectedExeption.expectMessage(StringStartsWith.startsWith("Unsupported or invalid encoding")); + + ServiceGroup newServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); + ExtensionType newExtension = new ExtensionType(); + newExtension.setExtensionID("new extension ID the second"); + newServiceGroup.getExtensions().add(newExtension); + + //when + serviceGroupService.saveServiceGroup(newServiceGroup, null, username, ADMIN_USERNAME); + + } + @Test public void urlsAreHandledByWebLayer() throws Throwable { //given @@ -128,7 +207,7 @@ public class ServiceGroupServiceSingleDomainIntegrationTest extends AbstractServ ServiceGroup newServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); //when-then - serviceGroupService.saveServiceGroup(newServiceGroup,"NOTEXISTINGDOMAIN", ADMIN_USERNAME); + serviceGroupService.saveServiceGroup(newServiceGroup,"NOTEXISTINGDOMAIN", ADMIN_USERNAME, ADMIN_USERNAME); } @Test(expected = WrongInputFieldException.class) @@ -137,7 +216,7 @@ public class ServiceGroupServiceSingleDomainIntegrationTest extends AbstractServ ServiceGroup newServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); //when-then - serviceGroupService.saveServiceGroup(newServiceGroup,"notAllowedChars:-_;#$", ADMIN_USERNAME); + serviceGroupService.saveServiceGroup(newServiceGroup,"notAllowedChars:-_;#$", ADMIN_USERNAME, ADMIN_USERNAME); } @Test @@ -146,7 +225,7 @@ public class ServiceGroupServiceSingleDomainIntegrationTest extends AbstractServ ServiceGroup newServiceGroup = unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); //when - serviceGroupService.saveServiceGroup(newServiceGroup,"domain1", ADMIN_USERNAME); + serviceGroupService.saveServiceGroup(newServiceGroup,"domain1", ADMIN_USERNAME, ADMIN_USERNAME); //then assertNotNull(serviceGroupService.getServiceGroup(SERVICE_GROUP_ID)); diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataIntegrationTest.java index 53620286b..ffbc90fd7 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataIntegrationTest.java @@ -79,7 +79,7 @@ public class ServiceMetadataIntegrationTest { @Before public void before() throws IOException { ServiceGroup inServiceGroup = ServiceGroupConverter.unmarshal(loadDocumentAsString(SERVICE_GROUP_XML_PATH)); - serviceGroupService.saveServiceGroup(inServiceGroup, null, ADMIN_USERNAME); + serviceGroupService.saveServiceGroup(inServiceGroup, null, ADMIN_USERNAME, ADMIN_USERNAME); } @Test diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java index 0bb2c8e93..0a0e9b52a 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java @@ -37,8 +37,6 @@ import java.io.UnsupportedEncodingException; import java.util.List; import static eu.europa.ec.smp.api.Identifiers.asParticipantId; -import static java.net.URLDecoder.decode; -import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.springframework.http.ResponseEntity.created; import static org.springframework.http.ResponseEntity.ok; @@ -53,8 +51,6 @@ public class ServiceGroupController { private static final Logger log = LoggerFactory.getLogger(ServiceGroupController.class); - private static final String UTF_8 = "UTF-8"; - @Autowired private ServiceGroupValidator serviceGroupValidator; @@ -86,9 +82,9 @@ public class ServiceGroupController { @PathVariable String serviceGroupId, @RequestHeader(name = "ServiceGroup-Owner", required = false) String serviceGroupOwner, @RequestHeader(name = "Domain", required = false) String domain, - @RequestBody String body) throws XmlInvalidAgainstSchemaException, UnsupportedEncodingException { + @RequestBody String body) throws XmlInvalidAgainstSchemaException { - log.info("PUT ServiceGroup: {}\n{}", serviceGroupId, body); + log.info("PUT ServiceGroup: {} domain {} owner {} \n{}", serviceGroupId,domain, serviceGroupOwner, body); // Validations BdxSmpOasisValidator.validateXSD(body); @@ -96,8 +92,7 @@ public class ServiceGroupController { serviceGroupValidator.validate(serviceGroupId, serviceGroup); // Service action - String newOwnerName = isNotBlank(serviceGroupOwner) ? decode(serviceGroupOwner, UTF_8) : SecurityContextHolder.getContext().getAuthentication().getName(); - boolean newServiceGroupCreated = serviceGroupService.saveServiceGroup(serviceGroup, domain, newOwnerName); + boolean newServiceGroupCreated = serviceGroupService.saveServiceGroup(serviceGroup, domain, serviceGroupOwner, SecurityContextHolder.getContext().getAuthentication().getName()); log.info("Finished PUT ServiceGroup: {}", serviceGroupId); -- GitLab