package org.mapfish.print.servlet; import com.google.common.collect.Maps; import org.json.JSONObject; import org.junit.After; import org.junit.Test; import org.mapfish.print.AbstractMapfishSpringTest; import org.mapfish.print.config.access.AccessAssertionTestUtil; import org.mapfish.print.test.util.ImageSimilarity; import org.mapfish.print.wrapper.json.PJsonObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.test.context.ContextConfiguration; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URISyntaxException; import java.util.Calendar; import java.util.HashMap; import javax.imageio.ImageIO; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @ContextConfiguration(locations = { MapPrinterServletSecurityTest.PRINT_CONTEXT }) public class MapPrinterServletSecurityTest extends AbstractMapfishSpringTest { public static final String PRINT_CONTEXT = "classpath:org/mapfish/print/servlet/mapfish-print-servlet.xml"; @Autowired private MapPrinterServlet servlet; @Autowired private ServletMapPrinterFactory printerFactory; @After public void tearDown() throws Exception { SecurityContextHolder.clearContext(); } @Test(timeout = 60000) public void testCreateReportAndGet_Success() throws Exception { AccessAssertionTestUtil.setCreds("ROLE_USER", "ROLE_EDITOR"); setUpConfigFiles(); final MockHttpServletRequest servletCreateRequest = new MockHttpServletRequest(); final MockHttpServletResponse servletCreateResponse = new MockHttpServletResponse(); String requestData = loadRequestDataAsString(); this.servlet.createReportAndGetNoAppId("png", requestData, false, servletCreateRequest, servletCreateResponse); assertEquals(HttpStatus.OK.value(), servletCreateResponse.getStatus()); assertCorrectResponse(servletCreateResponse); } @Test(timeout = 60000, expected = AccessDeniedException.class) public void testCreateReportAndGet_InsufficientPrivileges() throws Exception { AccessAssertionTestUtil.setCreds("ROLE_USER"); setUpConfigFiles(); final MockHttpServletRequest servletCreateRequest = new MockHttpServletRequest(); final MockHttpServletResponse servletCreateResponse = new MockHttpServletResponse(); String requestData = loadRequestDataAsString(); this.servlet.createReportAndGetNoAppId("png", requestData, false, servletCreateRequest, servletCreateResponse); } @Test(timeout = 60000, expected = AuthenticationCredentialsNotFoundException.class) public void testCreateReportAndGet_NoCredentials() throws Exception { setUpConfigFiles(); final MockHttpServletRequest servletCreateRequest = new MockHttpServletRequest(); final MockHttpServletResponse servletCreateResponse = new MockHttpServletResponse(); String requestData = loadRequestDataAsString(); this.servlet.createReportAndGetNoAppId("png", requestData, false, servletCreateRequest, servletCreateResponse); } @Test(timeout = 60000) public void testCreateReportAndGet_RequestAllowed_OtherGetDenied() throws Exception { AccessAssertionTestUtil.setCreds("ROLE_USER", "ROLE_EDITOR"); setUpConfigFiles(); final MockHttpServletRequest servletCreateRequest = new MockHttpServletRequest(); final MockHttpServletResponse servletCreateResponse = new MockHttpServletResponse(); String requestData = loadRequestDataAsString(); this.servlet.createReport("png", requestData, servletCreateRequest, servletCreateResponse); assertEquals(HttpStatus.OK.value(), servletCreateResponse.getStatus()); final JSONObject response = new JSONObject(servletCreateResponse.getContentAsString()); final String ref = response.getString(MapPrinterServlet.JSON_PRINT_JOB_REF); String statusURL = response.getString(MapPrinterServlet.JSON_STATUS_LINK); // wait until job is done boolean done = false; while (!done) { MockHttpServletRequest servletStatusRequest = new MockHttpServletRequest("GET", statusURL); MockHttpServletResponse servletStatusResponse = new MockHttpServletResponse(); servlet.getStatus(ref, null, servletStatusRequest, servletStatusResponse); String contentAsString = servletStatusResponse.getContentAsString(); final PJsonObject statusJson = parseJSONObjectFromString(contentAsString); assertTrue(statusJson.toString(), statusJson.has(MapPrinterServlet.JSON_DONE)); done = statusJson.getBool(MapPrinterServlet.JSON_DONE); if (!done) { Thread.sleep(500); } } try { AccessAssertionTestUtil.setCreds("ROLE_USER"); final MockHttpServletResponse getResponse1 = new MockHttpServletResponse(); this.servlet.getReport(ref, false, getResponse1); fail("Expected an AccessDeniedException"); } catch (AccessDeniedException e) { // good } SecurityContextHolder.clearContext(); try { final MockHttpServletResponse getResponse2 = new MockHttpServletResponse(); this.servlet.getReport(ref, false, getResponse2); assertEquals(HttpStatus.UNAUTHORIZED.value(), servletCreateResponse.getStatus()); fail("Expected an AuthenticationCredentialsNotFoundException"); } catch (AuthenticationCredentialsNotFoundException e) { // good } } private byte[] assertCorrectResponse(MockHttpServletResponse servletGetReportResponse) throws IOException { byte[] report; report = servletGetReportResponse.getContentAsByteArray(); final String contentType = servletGetReportResponse.getHeader("Content-Type"); assertEquals("image/png", contentType); final Calendar instance = Calendar.getInstance(); int year = instance.get(Calendar.YEAR); String fileName = servletGetReportResponse.getHeader("Content-disposition").split("=")[1]; assertEquals("test_report-" + year + ".png", fileName); final BufferedImage reportAsImage = ImageIO.read(new ByteArrayInputStream(report)); new ImageSimilarity(reportAsImage, 2).assertSimilarity(getFile(MapPrinterServletSecurityTest.class, "expectedSimpleImage.png"), 10); return report; } private void setUpConfigFiles() throws URISyntaxException { final HashMap<String, String> configFiles = Maps.newHashMap(); configFiles.put("default", getFile(MapPrinterServletSecurityTest.class, "config-security.yaml").getAbsolutePath()); printerFactory.setConfigurationFiles(configFiles); } private String loadRequestDataAsString() throws IOException { final PJsonObject requestJson = parseJSONObjectFromFile(MapPrinterServletSecurityTest.class, "requestData.json"); return requestJson.getInternalObj().toString(); } }