diff --git a/changelog.txt b/changelog.txt index c4f331a0a9ca9306846b9560498ee3c2262e8ff9..f728169b67df87917638ebe67519618a598f70b2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,5 @@ +eDelivery SMP 5.1 +- Added the HTTP parameter 'Resource-Owner' as alternative to ServiceGroup-Owner eDelivery SMP 5.0 - removed: bdmsl.participant.multidomain.enabled - environment properties have now 'smp.' prefix diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/security/DomainGuard.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/security/DomainGuard.java index 2e903b54c161f15ef425e7ee79913216489d708e..b7161e65d0b7a79af44d72bd629bae2d9e9834e7 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/security/DomainGuard.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/security/DomainGuard.java @@ -37,16 +37,17 @@ public class DomainGuard { /** * Method resolves the domain and authorize the user for the action on the domain + * * @param resourceRequest a resource request - * @param user a user trying to execute the action on the resource + * @param user a user trying to execute the action on the resource * @return the DBDomain */ - public DBDomain resolveAndAuthorizeForDomain(ResourceRequest resourceRequest, SMPUserDetails user){ + public DBDomain resolveAndAuthorizeForDomain(ResourceRequest resourceRequest, SMPUserDetails user) { DBDomain domain = domainResolverService.resolveDomain( resourceRequest.getDomainHttpParameter(), resourceRequest.getUrlPathParameter(0)); - if (isUserIsAuthorizedForDomainResourceAction(domain, user, resourceRequest.getAction())){ + if (isUserIsAuthorizedForDomainResourceAction(domain, user, resourceRequest.getAction())) { resourceRequest.setAuthorizedDomain(domain); return domain; } @@ -55,10 +56,11 @@ public class DomainGuard { } /** - * Purpose of the method is to guard domain resources. It validates if users has any "rights to" execute the action - * on the domain resources and subresources + * Purpose of the method is to guard domain resources and sub-resources. It validates if users has any + * "permission to" execute the http action on the domain resources and subresources. More accurate check is done + * when the resource and/or subresource are resolved. * - * @param user user to be authorized + * @param user user to be authorized * @param action action to be executed * @param domain domain to be authorized * @return true if user is authorized to execute the action on the domain @@ -82,9 +84,9 @@ public class DomainGuard { /** * Method validates of the user can read resources on the domain! * - * @param user - * @param domain - * @return + * @param user user to be authorized for READ action + * @param domain domain to be authorized + * @return true if user is authorized to execute the action on the domain, else it returns false */ public boolean canRead(SMPUserDetails user, DBDomain domain) { LOG.info(SMPLogger.SECURITY_MARKER, "User: [{}] is trying to read domain: [{}]", user, domain); @@ -112,7 +114,7 @@ public class DomainGuard { * Method validates of the user can delete resources on the domain! Only users with group admin role can delete * domain resources * - * @param user user to be authorized + * @param user user to be authorized * @param domain domain to be authorized * @return true if user is authorized to execute the action on the domain */ @@ -124,7 +126,8 @@ public class DomainGuard { return false; } // to be able to delete domain resources it must be member of any group on domain - boolean isAuthorized = groupMemberDao.isUserAnyDomainGroupResourceMemberWithRole(user.getUser(), domain, MembershipRoleType.ADMIN); + boolean isAuthorized = groupMemberDao.isUserAnyDomainGroupResourceMemberWithRole(user.getUser(), domain, MembershipRoleType.ADMIN) + || resourceMemberDao.isUserAnyDomainResourceMemberWithRole(user.getUser(), domain, MembershipRoleType.ADMIN); LOG.info(SMPLogger.SECURITY_MARKER, "User: [{}] is authorized:[{}] to read resources from Domain: [{}]", user, isAuthorized, domain); return isAuthorized; } @@ -135,7 +138,7 @@ public class DomainGuard { * * @param user user to be authorized * @param domain domain to be authorized - * @return true if user is authorized to execute the action on the domain + * @return true if user is authorized to execute the action on the domain */ public boolean canCreateUpdate(SMPUserDetails user, DBDomain domain) { LOG.info(SMPLogger.SECURITY_MARKER, "User: [{}] is trying to create/update resource from domain: [{}]", user, domain); @@ -145,12 +148,10 @@ public class DomainGuard { return false; } // to be able to delete domain resources it must be member of any group on domain - boolean isAuthorized = groupMemberDao.isUserAnyDomainGroupResourceMemberWithRole(user.getUser(), domain, MembershipRoleType.ADMIN) - || resourceMemberDao.isUserAnyDomainResourceMemberWithRole(user.getUser(), domain, MembershipRoleType.ADMIN); + boolean isAuthorized = groupMemberDao.isUserAnyDomainGroupResourceMemberWithRole(user.getUser(), domain, MembershipRoleType.ADMIN) + || resourceMemberDao.isUserAnyDomainResourceMemberWithRole(user.getUser(), domain, MembershipRoleType.ADMIN); LOG.info(SMPLogger.SECURITY_MARKER, "User: [{}] is authorized:[{}] to create/update resources from Domain: [{}]", user, isAuthorized, domain); return isAuthorized; } - - } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/security/ResourceGuard.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/security/ResourceGuard.java index 74d3ec329c7960c65a0febccd12f9510d6a6f5ca..5bdb857a06de55da7761f06e204b1c8ea9c3efc9 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/security/ResourceGuard.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/security/ResourceGuard.java @@ -44,7 +44,7 @@ public class ResourceGuard { * @param user user trying to execute the action * @param action resource action * @param resource target resource - * @return + * @return true if user is not authorized for the http action on the resource, else false. */ public boolean userIsNotAuthorizedForAction(SMPUserDetails user, ResourceAction action, DBResource resource, DBDomain domain) { return !userIsAuthorizedForAction(user, action, resource, domain); @@ -66,6 +66,8 @@ public class ResourceGuard { switch (action) { case READ: return canRead(user, subresource); + case CREATE_UPDATE: + return canCreateUpdate(user, subresource); case DELETE: return canDelete(user, subresource); } @@ -154,4 +156,10 @@ public class ResourceGuard { // Subresource can be created by the resource admin, the same as for update return canUpdate(user, subresource); } + + public boolean canCreateUpdate(SMPUserDetails user, DBSubresource subresource) { + LOG.debug(SMPLogger.SECURITY_MARKER, "User [{}] is trying to delete resource [{}]", user, subresource); + // Subresource can be created by the resource admin, the same as for update + return canUpdate(user, subresource); + } } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/ResourceResolverService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/ResourceResolverService.java index a6f07d1c36bf13aa3a82a0cc5d38ec3c71dbe13e..502259ace34a97f70f38f158b1e244cbbbac72ec 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/ResourceResolverService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/ResourceResolverService.java @@ -108,7 +108,7 @@ public class ResourceResolverService { validateResourceIdentifier(resourceId); DBResource resource = resolveResourceIdentifier(domain, resourceDef, resourceId); if (resource == null) { - // the resource must be found because it is not create action nor the last parameter to be resolved + // the resource must be found because if action is not "create" action nor the last parameter to be resolved if (resourceRequest.getAction() != ResourceAction.CREATE_UPDATE || pathParameters.size() > iParameterIndex + 1) { throw new SMPRuntimeException(ErrorCode.SG_NOT_EXISTS, resourceId.getValue(), resourceId.getScheme()); @@ -117,40 +117,51 @@ public class ResourceResolverService { } locationVector.setResource(resource); - if (resourceGuard.userIsNotAuthorizedForAction(user, resourceRequest.getAction(), resource, domain)) { - LOG.info(SECURITY_MARKER, "User [{}] is NOT authorized for action [{}] on the resource [{}]", getUsername(user), resourceRequest.getAction(), resource); - throw new SMPRuntimeException(ErrorCode.UNAUTHORIZED); - } else { - LOG.info(SECURITY_MARKER, "User: [{}] is authorized for action [{}] on the resource [{}]", getUsername(user), resourceRequest.getAction(), resource); - } - - if (pathParameters.size() == ++iParameterIndex) { - locationVector.setResolved(true); + // check if resource is resolved - no more parameters to be resolved + locationVector.setResolved(pathParameters.size() == ++iParameterIndex); + + if (locationVector.isResolved()) { + // validate if user is authorized for action + if (resourceGuard.userIsNotAuthorizedForAction(user, resourceRequest.getAction(), resource, domain)) { + LOG.info(SECURITY_MARKER, "User [{}] is NOT authorized for action [{}] on the resource [{}]", + getUsername(user), resourceRequest.getAction(), resource); + throw new SMPRuntimeException(ErrorCode.UNAUTHORIZED); + } return locationVector; } - if (pathParameters.size() == iParameterIndex + 2) { - String subResourceDefUrl = pathParameters.get(iParameterIndex); - // test if subresourceDef exists - DBSubresourceDef subresourceDef = getSubresource(resourceDef, subResourceDefUrl); - - Identifier subResourceId = identifierService.normalizeDocumentIdentifier(pathParameters.get(++iParameterIndex)); - DBSubresource subresource = resolveSubResourceIdentifier(resource, subResourceDefUrl, subResourceId); - LOG.debug("Got subresource [{}]", subresource); - if (subresource == null) { - if (resourceRequest.getAction() != ResourceAction.CREATE_UPDATE) { - throw new SMPRuntimeException(ErrorCode.METADATA_NOT_EXISTS, resource.getIdentifierValue(), resource.getIdentifierScheme(), subResourceId.getValue(), subResourceId.getScheme()); - } - subresource = createNewSubResource(subResourceId, resource, subresourceDef); + // resolve subresource - expected exactly two parameters + if (pathParameters.size() != iParameterIndex + 2) { + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, join(pathParameters, ","), + "Invalid remaining subresource parameters (expected only subresourceDef and subresource identifier)"); + + } + String subResourceDefUrl = pathParameters.get(iParameterIndex); + // test if subresourceDef exists + DBSubresourceDef subresourceDef = getSubresource(resourceDef, subResourceDefUrl); + Identifier subResourceId = identifierService.normalizeDocumentIdentifier(pathParameters.get(++iParameterIndex)); + DBSubresource subresource = resolveSubResourceIdentifier(resource, subResourceDefUrl, subResourceId); + LOG.debug("Got subresource [{}]", subresource); + if (subresource == null) { + if (resourceRequest.getAction() != ResourceAction.CREATE_UPDATE) { + throw new SMPRuntimeException(ErrorCode.METADATA_NOT_EXISTS, + resource.getIdentifierValue(), resource.getIdentifierScheme(), + subResourceId.getValue(), subResourceId.getScheme()); } + subresource = createNewSubResource(subResourceId, resource, subresourceDef); + } - locationVector.setSubresource(subresource); - locationVector.setSubResourceDef(subresourceDef); - locationVector.setResolved(true); - return locationVector; + if (!resourceGuard.userIsAuthorizedForAction(user, resourceRequest.getAction(), subresource)) { + LOG.info(SECURITY_MARKER, "User [{}] is NOT authorized for action [{}] on the subresource resource [{}]", + getUsername(user), resourceRequest.getAction(), subresource); + throw new SMPRuntimeException(ErrorCode.UNAUTHORIZED); } - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, join(pathParameters, ","), "Invalid remaining subresource parameters (expected only subresourceDef and subresource identifier)"); + locationVector.setSubresource(subresource); + locationVector.setSubResourceDef(subresourceDef); + locationVector.setResolved(true); + return locationVector; + } /** @@ -229,11 +240,17 @@ public class ResourceResolverService { optResDef = resourceDefs.stream().filter(resdef -> equalsIgnoreCase(resdef.getIdentifier(), domain.getDefaultResourceTypeIdentifier())).findFirst(); if (optResDef.isPresent()) { - LOG.debug("Located default ResourceDef [{}] for domain [{}] by the path parameter [{}]", domain.getDefaultResourceTypeIdentifier(), domain.getDomainCode()); + LOG.debug("Located default ResourceDef [{}] for domain [{}] by the path parameter [{}]", + domain.getDefaultResourceTypeIdentifier(), + domain.getDomainCode(), + pathParameter); return optResDef.get(); } // return first - LOG.info("Return first (default) ResourceDef [{}] for domain [{}] by the path parameter [{}]", resourceDefs.get(0).getDomainResourceDefs(), domain.getDomainCode()); + LOG.info("Return first (default) ResourceDef [{}] for domain [{}] by the path parameter [{}]", + resourceDefs.get(0).getDomainResourceDefs(), + domain.getDomainCode(), + pathParameter); return resourceDefs.get(0); } @@ -297,8 +314,7 @@ public class ResourceResolverService { } } - public String getUsername(UserDetails user){ - return user ==null? "Anonymous":user.getUsername(); + public String getUsername(UserDetails user) { + return user == null ? "Anonymous" : user.getUsername(); } - } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/servlet/ResourceRequest.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/servlet/ResourceRequest.java index 9cb62ab137465e775fbb1cf7f2e8f7b80f32f084..fada3aae2f4b9b89323fd2669f9dfab04b0028af 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/servlet/ResourceRequest.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/servlet/ResourceRequest.java @@ -2,6 +2,7 @@ package eu.europa.ec.edelivery.smp.servlet; import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.services.resource.ResolvedData; +import org.apache.commons.lang3.StringUtils; import java.io.InputStream; import java.util.List; @@ -42,7 +43,9 @@ public class ResourceRequest { public String getOwnerHttpParameter() { String owner = getHeader(WebConstants.HTTP_PARAM_OWNER); - + if (StringUtils.isBlank(owner)) { + owner = getHeader(WebConstants.HTTP_PARAM_OWNER_OBSOLETE); + } return owner; } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/servlet/WebConstants.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/servlet/WebConstants.java index a383ee43c5bcfe4dcec785a5f930093f81758c0d..14b117c4f4b67e8eb5ad6844a929c704ce1dc41b 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/servlet/WebConstants.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/servlet/WebConstants.java @@ -7,13 +7,13 @@ package eu.europa.ec.edelivery.smp.servlet; * @since 4.1 */ public class WebConstants { - public static final int HTTP_RESPONSE_CODE_CREATED= 201; - public static final int HTTP_RESPONSE_CODE_UPDATED= 200; - public static final String HTTP_PARAM_DOMAIN="Domain"; - public static final String HTTP_PARAM_RESOURCE_TYPE="Resource-Type"; - public static final String HTTP_PARAM_OWNER="ServiceGroup-Owner"; + public static final int HTTP_RESPONSE_CODE_CREATED = 201; + public static final int HTTP_RESPONSE_CODE_UPDATED = 200; + public static final String HTTP_PARAM_DOMAIN = "Domain"; + public static final String HTTP_PARAM_RESOURCE_TYPE = "Resource-Type"; + public static final String HTTP_PARAM_OWNER_OBSOLETE = "ServiceGroup-Owner"; + public static final String HTTP_PARAM_OWNER = "Resource-Owner"; private WebConstants() { } - } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/security/ResourceGuardTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/security/ResourceGuardTest.java index 18865ac0e4f77fec8db04e664c20793d4347181a..a0b02ca62ae4f6a736506b1700c95402fad09bf8 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/security/ResourceGuardTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/security/ResourceGuardTest.java @@ -3,11 +3,8 @@ package eu.europa.ec.edelivery.smp.security; import eu.europa.ec.edelivery.smp.auth.SMPUserDetails; import eu.europa.ec.edelivery.smp.data.dao.AbstractJunit5BaseDao; import eu.europa.ec.edelivery.smp.data.enums.VisibilityType; -import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; import eu.europa.ec.edelivery.smp.servlet.ResourceAction; import eu.europa.ec.edelivery.smp.servlet.ResourceRequest; -import org.hamcrest.CoreMatchers; -import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -22,8 +19,6 @@ class ResourceGuardTest extends AbstractJunit5BaseDao { @Autowired ResourceGuard testInstance; - - ResourceRequest resourceRequest = Mockito.mock(ResourceRequest.class); SMPUserDetails userDetails = Mockito.mock(SMPUserDetails.class); @BeforeEach @@ -57,18 +52,6 @@ class ResourceGuardTest extends AbstractJunit5BaseDao { assertTrue(result); } - @ParameterizedTest - @ValueSource(strings = {"CREATE_UPDATE"}) - void testUserIsAuthorizedForActionNotSupported(ResourceAction action) { - // given - user is authorized - see the createResourceMemberships - when(userDetails.getUser()).thenReturn(testUtilsDao.getUser1()); - SMPRuntimeException result = assertThrows(SMPRuntimeException.class, - () -> testInstance.userIsAuthorizedForAction(userDetails, action, testUtilsDao.getSubresourceD1G1RD1_S1())); - - // then - MatcherAssert.assertThat(result.getMessage(), CoreMatchers.containsString("Action not supported")); - } - @Test void testCanReadResourceForPrivateDomainOK() { // given - user is authorized - see the createResourceMemberships diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ResourceController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ResourceController.java index b649cf1c2781c7f4f05a86e6f1e34bf71808ba09..125be50e44c1d944eeb38086675d0ecf9d9c6b2a 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ResourceController.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ResourceController.java @@ -51,6 +51,7 @@ public class ResourceController { // set them to lower case for fast comparing with the http headers private static final List<String> SUPPORTED_HEADERS = Arrays.asList(lowerCase(HTTP_PARAM_DOMAIN), lowerCase(HTTP_PARAM_OWNER), + lowerCase(HTTP_PARAM_OWNER_OBSOLETE), lowerCase(HTTP_PARAM_RESOURCE_TYPE)); final ResourceService resourceService; final DomainGuard domainGuard; @@ -131,7 +132,6 @@ public class ResourceController { } // resolve domain and test authorization for the domain. domainGuard.resolveAndAuthorizeForDomain(resourceRequest, user); - return user; } diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerSingleDomainTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerSingleDomainTest.java index c2385f02f1cea7350a829c4c1309e393115fc04b..d78a559dc0c919742238f007c9c12b166a8050a2 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerSingleDomainTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerSingleDomainTest.java @@ -13,149 +13,99 @@ package eu.europa.ec.edelivery.smp.controllers; -import eu.europa.ec.edelivery.smp.test.SmpTestWebAppConfig; -import eu.europa.ec.edelivery.smp.test.testutils.X509CertificateTestUtils; -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.jdbc.Sql; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -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 eu.europa.ec.edelivery.smp.ui.AbstractControllerTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.platform.commons.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; + import java.io.IOException; -import static eu.europa.ec.edelivery.smp.ServiceGroupBodyUtil.*; +import static eu.europa.ec.edelivery.smp.ServiceGroupBodyUtil.getSampleServiceGroupBodyWithScheme; import static java.lang.String.format; import static org.hamcrest.Matchers.stringContainsInOrder; import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; -import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_METHOD; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** - * Created by gutowpa on 02/08/2017. + * @author gutowpa + * @since 3.0 */ -@RunWith(SpringRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = {SmpTestWebAppConfig.class}) -@Sql(scripts = {"classpath:/cleanup-database.sql", - "classpath:/webapp_integration_test_data.sql"}, - executionPhase = BEFORE_TEST_METHOD) -public class ResourceControllerSingleDomainTest { - - private static final String IDENTIFIER_SCHEME = "ehealth-participantid-qns"; - private static final String PARTICIPANT_ID = "urn:poland:ncpb"; - - private static final String DOCUMENT_SCHEME = "doctype"; - private static final String DOCUMENT_ID = "invoice"; +public class ResourceControllerSingleDomainTest extends AbstractControllerTest { - private static final String URL_PATH = format("/%s::%s", IDENTIFIER_SCHEME, PARTICIPANT_ID); - private static final String URL_DOC_PATH = format("%s/services/%s::%s", URL_PATH, DOCUMENT_SCHEME, DOCUMENT_ID); + public static final Logger LOG = LoggerFactory.getLogger(ResourceControllerSingleDomainTest.class); private static final String SERVICE_GROUP_INPUT_BODY = getSampleServiceGroupBodyWithScheme(IDENTIFIER_SCHEME); private static final String HTTP_HEADER_KEY_DOMAIN = "Domain"; private static final String HTTP_HEADER_KEY_SERVICE_GROUP_OWNER = "ServiceGroup-Owner"; private static final String OTHER_OWNER_NAME = "CN=EHEALTH_SMP_TEST_BRAZIL,O=European Commission,C=BE:48b681ee8e0dcc08"; - private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("pat_smp_admin", "123456"); - - @Autowired - private WebApplicationContext webAppContext; - - private MockMvc mvc; - - @Before - public void setup() throws IOException { - X509CertificateTestUtils.reloadKeystores(); - 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); - listener.contextInitialized(event); + @BeforeEach + void initApplication() throws IOException { + super.setup(); } @Test - public void adminCanCreateServiceGroupNoDomain() throws Exception { + void adminCanCreateServiceGroupNoDomain() throws Exception { mvc.perform(put(URL_PATH) - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - .content(SERVICE_GROUP_INPUT_BODY)) + .with(ADMIN_CREDENTIALS) + .contentType(APPLICATION_XML_VALUE) + .content(SERVICE_GROUP_INPUT_BODY)) .andExpect(status().isCreated()); } - @Test - public void adminCanUpdateServiceGroupNoDomain() throws Exception { - mvc.perform(put(URL_PATH) + /** + * Test update permissions for resource with different creation parameters. The user data match + * the data in the database: webapp_integration_test_data.sql + */ + @ParameterizedTest + @CsvSource({"'Default owner is admin: OK', 200, pat_smp_admin, 123456,''", + "'Default owner Admin, but user updates: Fail', 401, test_pat_hashed_pass, 123456,''", + "'Default owner is admin, bad credentials: Fail', 401, pat_smp_admin, 000000,''", + "'Set owner is same group admin: OK', 200, pat_smp_admin, 123456,'pat_smp_admin'", + "'Set owner user: OK', 200, test_pat_hashed_pass, 123456,'test_pat_hashed_pass'", + "'Set owner username: OK', 200, test_pat_hashed_pass, 123456,'test_user_hashed_pass'", + "'Set owner user, but admin updates: Fail', 401, test_pat_hashed_pass, 123456,'pat_smp_admin'", + }) + void groupAdminCanUpdateServiceGroupNoDomain(String desc, int expectedStatus, + String resourceAdminATId, String groupResourceATSecret, + String resourceOwnerId) throws Exception { + LOG.info(desc); + // create service group by group admin + HttpHeaders httpHeaders = new HttpHeaders(); + if (StringUtils.isNotBlank(resourceOwnerId)) { + httpHeaders.add(HTTP_HEADER_KEY_SERVICE_GROUP_OWNER, resourceOwnerId); + } - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - .content(SERVICE_GROUP_INPUT_BODY)) + mvc.perform(put(URL_PATH) + .with(ADMIN_CREDENTIALS) + .contentType(APPLICATION_XML_VALUE) + .headers(httpHeaders) + .content(SERVICE_GROUP_INPUT_BODY)) .andExpect(status().isCreated()); - + // update service group by owner (if not given then owner is the same as creator) mvc.perform(put(URL_PATH) - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - .content(SERVICE_GROUP_INPUT_BODY)) - .andExpect(status().isOk()); + .with(httpBasic(resourceAdminATId, groupResourceATSecret)) + .contentType(APPLICATION_XML_VALUE) + .content(SERVICE_GROUP_INPUT_BODY)) + .andExpect(status().is(expectedStatus)); } @Test - public void existingServiceMetadataCanBeRetrievedByEverybodyNoDomain() throws Exception { - - String xmlSG = getSampleServiceGroupBody(IDENTIFIER_SCHEME, PARTICIPANT_ID); - String xmlMD = generateServiceMetadata(PARTICIPANT_ID, IDENTIFIER_SCHEME, DOCUMENT_ID, DOCUMENT_SCHEME, "test"); - // crate service group - mvc.perform(put(URL_PATH) - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - .content(xmlSG)) - .andExpect(status().isCreated()); - // add service metadata - mvc.perform(put(URL_DOC_PATH) - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - - .content(xmlMD)) - .andExpect(status().isCreated()); - - MvcResult mr = mvc.perform(get(URL_PATH).header("X-Forwarded-Host", "ec.test.eu") - .header("X-Forwarded-Port", "443") - .header("X-Forwarded-Proto", "https")).andReturn(); - System.out.println(mr.getResponse().getContentAsString()); - mvc.perform(get(URL_PATH)) - .andExpect(content().xml("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><ServiceGroup xmlns=\"http://docs.oasis-open.org/bdxr/ns/SMP/2016/05\" xmlns:ns2=\"http://www.w3.org/2000/09/xmldsig#\"><ParticipantIdentifier scheme=\"ehealth-participantid-qns\">urn:poland:ncpb</ParticipantIdentifier><ServiceMetadataReferenceCollection><ServiceMetadataReference href=\"http://localhost/ehealth-participantid-qns%3A%3Aurn%3Apoland%3Ancpb/services/doctype%3A%3Ainvoice\"/></ServiceMetadataReferenceCollection></ServiceGroup>")); - - } - - @Test - public void anonymousUserCannotCreateServiceGroup() throws Exception { + void anonymousUserCannotCreateServiceGroup() throws Exception { mvc.perform(put(URL_PATH) - .contentType(APPLICATION_XML_VALUE) - .content(SERVICE_GROUP_INPUT_BODY)) + .contentType(APPLICATION_XML_VALUE) + .content(SERVICE_GROUP_INPUT_BODY)) .andExpect(status().isUnauthorized()); mvc.perform(get(URL_PATH)) @@ -163,56 +113,56 @@ public class ResourceControllerSingleDomainTest { } @Test - public void malformedInputReturnsBadRequestNoDomain() throws Exception { + void malformedInputReturnsBadRequestNoDomain() throws Exception { mvc.perform(put(URL_PATH) - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - .content("malformed input XML")) + .with(ADMIN_CREDENTIALS) + .contentType(APPLICATION_XML_VALUE) + .content("malformed input XML")) .andExpect(status().isBadRequest()); } @Test - public void invalidParticipantSchemeReturnsBadRequestNoDomain() throws Exception { + void invalidParticipantSchemeReturnsBadRequestNoDomain() throws Exception { String scheme = "length-exceeeeeeds-25chars"; String urlPath = format("/%s::%s", scheme, PARTICIPANT_ID); mvc.perform(put(urlPath) - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - .content(getSampleServiceGroupBodyWithScheme(scheme))) + .with(ADMIN_CREDENTIALS) + .contentType(APPLICATION_XML_VALUE) + .content(getSampleServiceGroupBodyWithScheme(scheme))) .andExpect(status().isBadRequest()); } @Test - public void creatingServiceGroupUnderBadFormatedDomainReturnsBadRequestNoDomain() throws Exception { + void creatingServiceGroupUnderBadFormattedDomainReturnsBadRequestNoDomain() throws Exception { mvc.perform(put(URL_PATH) - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - .header(HTTP_HEADER_KEY_DOMAIN, "not-existing-domain") - .content(SERVICE_GROUP_INPUT_BODY)) + .with(ADMIN_CREDENTIALS) + .contentType(APPLICATION_XML_VALUE) + .header(HTTP_HEADER_KEY_DOMAIN, "not-existing-domain") + .content(SERVICE_GROUP_INPUT_BODY)) .andExpect(status().isBadRequest()) .andExpect(content().string(stringContainsInOrder("FORMAT_ERROR"))); } @Test - public void creatingServiceGroupUnderNotExistingDomainReturnsBadRequestNoDomain() throws Exception { + void creatingServiceGroupUnderNotExistingDomainReturnsBadRequestNoDomain() throws Exception { mvc.perform(put(URL_PATH) - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - .header(HTTP_HEADER_KEY_DOMAIN, "notExistingDomain") - .content(SERVICE_GROUP_INPUT_BODY)) + .with(ADMIN_CREDENTIALS) + .contentType(APPLICATION_XML_VALUE) + .header(HTTP_HEADER_KEY_DOMAIN, "notExistingDomain") + .content(SERVICE_GROUP_INPUT_BODY)) .andExpect(status().isNotFound()) .andExpect(content().string(stringContainsInOrder("NOT_FOUND"))); } @Test - public void adminCanAssignNewServiceGroupToOtherOwnerNoDomain() throws Exception { + void adminCanAssignNewServiceGroupToOtherOwnerNoDomain() throws Exception { mvc.perform(put(URL_PATH) - .with(ADMIN_CREDENTIALS) - .contentType(APPLICATION_XML_VALUE) - .header(HTTP_HEADER_KEY_SERVICE_GROUP_OWNER, OTHER_OWNER_NAME) - .content(SERVICE_GROUP_INPUT_BODY)) + .with(ADMIN_CREDENTIALS) + .contentType(APPLICATION_XML_VALUE) + .header(HTTP_HEADER_KEY_SERVICE_GROUP_OWNER, OTHER_OWNER_NAME) + .content(SERVICE_GROUP_INPUT_BODY)) .andExpect(status().isCreated()); } } diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerSubResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerSubResourceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e3ebe8d28ff6b4639e8d7c16d67bfac6c0fa8a4a --- /dev/null +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerSubResourceTest.java @@ -0,0 +1,152 @@ +package eu.europa.ec.edelivery.smp.controllers; + +import eu.europa.ec.edelivery.smp.servlet.WebConstants; +import eu.europa.ec.edelivery.smp.ui.AbstractControllerTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.platform.commons.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.test.web.servlet.MvcResult; + +import java.io.IOException; + +import static eu.europa.ec.edelivery.smp.ServiceGroupBodyUtil.generateServiceMetadata; +import static eu.europa.ec.edelivery.smp.ServiceGroupBodyUtil.getSampleServiceGroupBody; +import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class ResourceControllerSubResourceTest extends AbstractControllerTest { + + public static final Logger LOG = LoggerFactory.getLogger(ResourceControllerSingleDomainTest.class); + + private static final String IDENTIFIER_SCHEME = "ehealth-participantid-qns"; + private static final String DOCUMENT_SCHEME = "doctype"; + + + @BeforeEach + public void setup() throws IOException { + super.setup(); + } + + /** + * Test update permissions for resource with different creation parameters. The user data match + * the data in the database: webapp_integration_test_data.sql + */ + @ParameterizedTest + @CsvSource({"'Resource owner is admin: OK', 201, pat_smp_admin, 123456,''", + "'Resource owner, but user updates: Fail', 401, test_pat_hashed_pass, 123456,''", + "'Default owner is admin, bad credentials: Fail', 401, pat_smp_admin, 000000,''", + "'Set owner is same group admin: OK', 201, pat_smp_admin, 123456,'pat_smp_admin'", + "'Set owner user: OK', 201, test_pat_hashed_pass, 123456,'test_pat_hashed_pass'", + "'Set owner username: OK', 201, test_pat_hashed_pass, 123456,'test_user_hashed_pass'", + "'Set owner user, but admin updates: Fail', 401, test_pat_hashed_pass, 123456,'pat_smp_admin'", + }) + void createSubResourcePermissions(String desc, int expectedStatus, + String resourceAdminATId, String resourceATSecret, + String resourceOwnerId) throws Exception { + LOG.info(desc); + + String xmlSG = getSampleServiceGroupBody(IDENTIFIER_SCHEME, PARTICIPANT_ID); + String xmlMD = generateServiceMetadata(PARTICIPANT_ID, IDENTIFIER_SCHEME, DOCUMENT_ID, DOCUMENT_SCHEME, "test"); + // owner headers + HttpHeaders httpHeaders = new HttpHeaders(); + if (StringUtils.isNotBlank(resourceOwnerId)) { + httpHeaders.add(WebConstants.HTTP_PARAM_OWNER, resourceOwnerId); + } + // crate service group + mvc.perform(put(URL_PATH) + .with(ADMIN_CREDENTIALS) + .headers(httpHeaders) + .contentType(APPLICATION_XML_VALUE) + .content(xmlSG)) + .andExpect(status().isCreated()); + // add subresource/service-metadata + mvc.perform(put(URL_DOC_PATH) + .with(httpBasic(resourceAdminATId, resourceATSecret)) + .contentType(APPLICATION_XML_VALUE) + .content(xmlMD)) + .andExpect(status().is(expectedStatus)); + } + + /** + * Test update permissions for resource with different creation parameters. The user data match + * the data in the database: webapp_integration_test_data.sql + */ + @ParameterizedTest + @CsvSource({"'Resource owner is admin: OK', 200, pat_smp_admin, 123456, pat_smp_admin, 123456, ''", + "'Admin is Resource owner, but user deletes: Fail', 401, pat_smp_admin, 123456, test_pat_hashed_pass, 123456,''", + "'Default owner is admin, bad credentials: Fail', 401, pat_smp_admin, 123456, pat_smp_admin, 000000,''", + "'Set owner is same group admin: OK', 200, pat_smp_admin, 123456, pat_smp_admin, 123456,'pat_smp_admin'", + "'Set resource owner user: OK', 200, test_pat_hashed_pass, 123456, test_pat_hashed_pass, 123456,'test_pat_hashed_pass'", + "'Set resource owner user: OK', 200, test_pat_hashed_pass, 123456, test_pat_hashed_pass, 123456,'test_user_hashed_pass'", + "'Set owner user, but admin deletets: Fail', 400, test_pat_hashed_pass, 123456, pat_smp_admin, 123456, 'test_pat_hashed_pass'", + }) + void deleteSubResourcePermissions(String desc, int expectedStatus, + String resourceAdminCreateATId, String resourceCreateATSecret, + String deleteAdminCreateATId, String deleteCreateATSecret, + String resourceOwnerId) throws Exception { + LOG.info(desc); + + String xmlSG = getSampleServiceGroupBody(IDENTIFIER_SCHEME, PARTICIPANT_ID); + String xmlMD = generateServiceMetadata(PARTICIPANT_ID, IDENTIFIER_SCHEME, DOCUMENT_ID, DOCUMENT_SCHEME, "test"); + // owner headers + HttpHeaders httpHeaders = new HttpHeaders(); + if (StringUtils.isNotBlank(resourceOwnerId)) { + httpHeaders.add(WebConstants.HTTP_PARAM_OWNER, resourceOwnerId); + } + // crate service group + mvc.perform(put(URL_PATH) + .with(ADMIN_CREDENTIALS) + .headers(httpHeaders) + .contentType(APPLICATION_XML_VALUE) + .content(xmlSG)) + .andExpect(status().isCreated()); + // add subresource/service-metadata with appropriate owner + mvc.perform(put(URL_DOC_PATH) + .with(httpBasic(resourceAdminCreateATId, resourceCreateATSecret)) + .contentType(APPLICATION_XML_VALUE) + .content(xmlMD)) + .andExpect(status().isCreated()); + + // delete subresource/service-metadata with test owner + mvc.perform(delete(URL_DOC_PATH) + .with(httpBasic(deleteAdminCreateATId, deleteCreateATSecret))) + .andExpect(status().is(expectedStatus)); + } + + @Test + void existingSubResourceCanBeRetrievedByEverybodyNoDomain() throws Exception { + + String xmlSG = getSampleServiceGroupBody(IDENTIFIER_SCHEME, PARTICIPANT_ID); + String xmlMD = generateServiceMetadata(PARTICIPANT_ID, IDENTIFIER_SCHEME, DOCUMENT_ID, DOCUMENT_SCHEME, "test"); + // crate service group + mvc.perform(put(URL_PATH) + .with(ADMIN_CREDENTIALS) + .contentType(APPLICATION_XML_VALUE) + .content(xmlSG)) + .andExpect(status().isCreated()); + // add service metadata + + mvc.perform(put(URL_DOC_PATH) + .with(ADMIN_CREDENTIALS) + .contentType(APPLICATION_XML_VALUE) + + .content(xmlMD)) + .andExpect(status().isCreated()); + + MvcResult mr = mvc.perform(get(URL_PATH).header("X-Forwarded-Host", "ec.test.eu") + .header("X-Forwarded-Port", "443") + .header("X-Forwarded-Proto", "https")).andReturn(); + System.out.println(mr.getResponse().getContentAsString()); + mvc.perform(get(URL_PATH)) + .andExpect(content().xml("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><ServiceGroup xmlns=\"http://docs.oasis-open.org/bdxr/ns/SMP/2016/05\" xmlns:ns2=\"http://www.w3.org/2000/09/xmldsig#\"><ParticipantIdentifier scheme=\"ehealth-participantid-qns\">urn:poland:ncpb</ParticipantIdentifier><ServiceMetadataReferenceCollection><ServiceMetadataReference href=\"http://localhost/ehealth-participantid-qns%3A%3Aurn%3Apoland%3Ancpb/services/doctype%3A%3Ainvoice\"/></ServiceMetadataReferenceCollection></ServiceGroup>")); + + } +} diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerTest.java index fc40c3c2825b2e8f06dd30a6792e2b4a74d6d6f8..3a820e0e3a21c5769e9e4acc8da616e093cdd57d 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ResourceControllerTest.java @@ -23,7 +23,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.web.servlet.ResultActions; -import org.springframework.test.web.servlet.request.RequestPostProcessor; import org.springframework.web.server.adapter.ForwardedHeaderTransformer; import java.io.IOException; @@ -35,7 +34,6 @@ import static eu.europa.ec.edelivery.smp.ServiceGroupBodyUtil.getSampleServiceGr import static java.lang.String.format; import static org.hamcrest.Matchers.stringContainsInOrder; import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -50,9 +48,6 @@ public class ResourceControllerTest extends AbstractControllerTest { private static final String DOCUMENT_TYPE_URL = "smp-1"; - private static final String IDENTIFIER_SCHEME = "ehealth-participantid-qns"; - private static final String DOCUMENT_SCHEME = "doctype"; - private static final String HTTP_HEADER_KEY_DOMAIN = "Domain"; private static final String HTTP_HEADER_KEY_SERVICE_GROUP_OWNER = "ServiceGroup-Owner"; private static final String HTTP_DOMAIN_VALUE = "domain"; @@ -60,8 +55,6 @@ public class ResourceControllerTest extends AbstractControllerTest { private static final String OTHER_OWNER_NAME_URL_ENCODED = "CN=utf-8_%C5%BC_SMP,O=EC,C=BE:0000000000000666"; - private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("pat_smp_admin", "123456"); - @Autowired ForwardedHeaderTransformer forwardedHeaderTransformer; @@ -368,7 +361,6 @@ public class ResourceControllerTest extends AbstractControllerTest { public void malformedInputReturnsBadRequest() throws Exception { String participantId = UUID.randomUUID().toString(); - String resourceExample = getSampleServiceGroupBody(IDENTIFIER_SCHEME, participantId); String urlPath = format("/%s::%s", IDENTIFIER_SCHEME, participantId); mvc.perform(put(urlPath) @@ -476,7 +468,7 @@ public class ResourceControllerTest extends AbstractControllerTest { .andExpect(status().isCreated()); // add service metadata LOG.info("create service metadata: [{}]", docUrlPath); - ResultActions actions = mvc.perform(put(docUrlPath) + mvc.perform(put(docUrlPath) .header(HTTP_HEADER_KEY_DOMAIN, HTTP_DOMAIN_VALUE) .with(ADMIN_CREDENTIALS) .contentType(APPLICATION_XML_VALUE) diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/server/security/SecurityConfigurationClientCertTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/server/security/SecurityConfigurationClientCertTest.java index 9d75fbd2b3499d1b9ae55efd2e64a21e98d5c243..4a6effcb052f62f4059c7bcc7438dc0231fd2358 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/server/security/SecurityConfigurationClientCertTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/server/security/SecurityConfigurationClientCertTest.java @@ -19,18 +19,19 @@ import eu.europa.ec.edelivery.smp.data.dao.ConfigurationDao; import eu.europa.ec.edelivery.smp.test.SmpTestWebAppConfig; import eu.europa.ec.edelivery.smp.test.testutils.MockMvcUtils; import eu.europa.ec.edelivery.smp.test.testutils.X509CertificateTestUtils; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.junit4.rules.SpringClassRule; -import org.springframework.test.context.junit4.rules.SpringMethodRule; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; @@ -50,15 +51,16 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. /** * Created by gutowpa on 20/02/2017. */ - -@RunWith(Parameterized.class) +@ExtendWith(SpringExtension.class) @WebAppConfiguration @ContextConfiguration(classes = {SmpTestWebAppConfig.class}) +@DirtiesContext @Sql(scripts = { "classpath:/cleanup-database.sql", "classpath:/webapp_integration_test_data.sql"}, executionPhase = BEFORE_TEST_METHOD) public class SecurityConfigurationClientCertTest { + public static final Logger LOG = LoggerFactory.getLogger(SecurityConfigurationClientCertTest.class); //Jul++9+23:59:00+2019+GMT" private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("MMM dd HH:mm:ss yyyy 'GMT'"); @@ -133,18 +135,9 @@ public class SecurityConfigurationClientCertTest { "C=DE, O=T-Systems International GmbH, OU=T-Systems Trust Center, ST=Nordrhein Westfalen, postalCode=57250, L=Netphen, street=Untere Industriestr. 20, CN=Internal Business CA 2", "f71ee8b11cb3b787", }, - - }); } - // because we are using Parameterized instead of SpringJUnit4ClassRunner we need to declare - // SpringClassRule and SpringMethodRule manually - @ClassRule - public static final SpringClassRule scr = new SpringClassRule(); - @Rule - public final SpringMethodRule smr = new SpringMethodRule(); - @Autowired private WebApplicationContext context; @@ -153,7 +146,7 @@ public class SecurityConfigurationClientCertTest { MockMvc mvc; - @Before + @BeforeEach public void setup() throws IOException { configurationDao.setPropertyToDatabase(SMPPropertyEnum.EXTERNAL_TLS_AUTHENTICATION_CLIENT_CERT_HEADER_ENABLED, "true", ""); configurationDao.setPropertyToDatabase(SMPPropertyEnum.CLIENT_CERT_HEADER_ENABLED_DEPRECATED, "true", ""); @@ -161,30 +154,23 @@ public class SecurityConfigurationClientCertTest { X509CertificateTestUtils.reloadKeystores(); mvc = MockMvcUtils.initializeMockMvc(context); - } - @Parameterized.Parameter() - public String testName; - - @Parameterized.Parameter(1) - public String expectedCertificateId; - - @Parameterized.Parameter(2) - public String certificateDn; - - @Parameterized.Parameter(3) - public String serialNumber; - - @Test - public void validClientCertHeaderAuthorizedForPutTest() throws Exception { - System.out.println("Test: " + testName); + @ParameterizedTest + @MethodSource("data") + public void validClientCertHeaderAuthorizedForPutTest( + String testName, + String expectedCertificateId, + String certificateDn, + String serialNumber + ) throws Exception { + LOG.info("Test: [{}]", testName); String clientCert = buildClientCert(serialNumber, certificateDn); System.out.println("Client-Cert: " + clientCert); HttpHeaders headers = new HttpHeaders(); headers.add("Client-Cert", clientCert); mvc.perform(MockMvcRequestBuilders.put(RETURN_LOGGED_USER_PATH) - .headers(headers).with(csrf())) + .headers(headers).with(csrf())) .andExpect(status().isOk()) .andExpect(content().string(containsString(expectedCertificateId))) .andReturn().getResponse().getContentAsString(); diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AbstractControllerTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AbstractControllerTest.java index c18993834ee04da04a55e7a2f1cd7cb284cdf6a2..92f313929d0707d80dc991653ee6a237c8cccffc 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AbstractControllerTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AbstractControllerTest.java @@ -21,6 +21,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.RequestPostProcessor; import org.springframework.web.context.WebApplicationContext; import java.io.IOException; @@ -31,7 +32,9 @@ import java.util.stream.Collectors; import static eu.europa.ec.edelivery.smp.test.testutils.MockMvcUtils.getObjectFromResponse; import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.*; +import static java.lang.String.format; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_METHOD; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; @@ -47,6 +50,20 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. executionPhase = BEFORE_TEST_METHOD) abstract public class AbstractControllerTest { + // the webapp_integration_test_data data + public static final String IDENTIFIER_SCHEME = "ehealth-participantid-qns"; + public static final String DOCUMENT_SCHEME = "doctype"; + + + public static final String PARTICIPANT_ID = "urn:poland:ncpb"; + public static final String DOCUMENT_ID = "invoice"; + + public static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("pat_smp_admin", "123456"); + + // Oasis SMP 1.0 URL paths + public static final String URL_PATH = format("/%s::%s", IDENTIFIER_SCHEME, PARTICIPANT_ID); + public static final String URL_DOC_PATH = format("%s/services/%s::%s", URL_PATH, DOCUMENT_SCHEME, DOCUMENT_ID); + protected ObjectMapper mapper = null; protected MockMvc mvc; @Autowired