package servlets.module.lesson; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import dbProcs.GetterIT; import dbProcs.Setter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Locale; import java.util.Properties; import java.util.ResourceBundle; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockServletConfig; import testUtils.TestProperties; import utils.InstallationException; public class XxeLessonIT { private static final String LANGUAGE_CODE = "en_GB"; private static final Logger log = LogManager.getLogger(XxeLessonIT.class); private static String applicationRoot = new String(); private MockHttpServletRequest request; private MockHttpServletResponse response; private static final String MODULE_CLASS_NAME = "XxeLesson"; private static String TEST_USERNAME = "lessonTester"; private static ResourceBundle errors; /** Creates DB or Restores DB to Factory Defaults before running tests */ @BeforeAll public static void before() { Locale enLocale = Locale.forLanguageTag(LANGUAGE_CODE); errors = ResourceBundle.getBundle("i18n.servlets.errors", enLocale); TestProperties.setTestPropertiesFileDirectory(log); try { TestProperties.ensureSchemaReady(log); TestProperties.reseedTestData(); TestProperties.createFileSystemKey(log, "xxe.lesson.file", "xxe.lesson.solution"); GetterIT.verifyTestUser(applicationRoot, TEST_USERNAME, TEST_USERNAME); } catch (InstallationException e) { String message = "Could not create DB: " + e.toString(); log.fatal(message); fail(message); } catch (Exception e) { log.fatal("Could not initialise test"); fail(e.toString()); } } @BeforeEach public void setup() { request = new MockHttpServletRequest(); response = new MockHttpServletResponse(); // Open All modules if (!Setter.openAllModules(applicationRoot, false) && !Setter.openAllModules(applicationRoot, true)) { fail("Could not Mark All Modules As Open"); } } public String doMockPost(byte[] xmlEmail, String csrfToken, int expectedResponseCode) throws Exception { log.debug("Creating " + MODULE_CLASS_NAME + " Servlet Instance"); try { XxeLesson servlet = new XxeLesson(); servlet.init(new MockServletConfig(MODULE_CLASS_NAME)); request.setContentType("application/xml"); log.debug("Setting Up Params and Atrributes"); request.setContent(xmlEmail); // for an XML payload use setContent instead of addParameter // Adding Correct CSRF Token (Token Submitted) request.addHeader("csrfToken", csrfToken); log.debug("Running doPost"); servlet.doPost(request, response); assertFalse(response.getStatus() != expectedResponseCode); return (response.getContentAsString()); } catch (Exception e) { fail(e.toString()); throw e; } } @Test public void testLevelValidAnswerXxeInjection() { Setter.openAllModules(applicationRoot, true); try { // Sign in as Normal User log.debug("Signing in as " + TEST_USERNAME + " Through LoginServlet"); TestProperties.loginDoPost( log, request, response, TEST_USERNAME, TEST_USERNAME, null, LANGUAGE_CODE); log.debug("Login Servlet Complete, Getting CSRF Token"); String csrfToken = response.getCookie("token").getValue(); assertFalse(csrfToken.isEmpty()); Properties prop = new Properties(); try (InputStream xxe_input = new FileInputStream( System.getProperty("user.dir") + "/src/main/resources/fileSystemKeys.properties")) { prop.load(xxe_input); } catch (IOException e) { log.error("Could not load properties file: " + e.toString()); throw new RuntimeException(e); } String errorBase = "Missing property :"; String filename = prop.getProperty("xxe.lesson.file"); if (filename == null) { throw new RuntimeException(errorBase + "xxe.lesson.file"); } request.setCookies(response.getCookies()); String xxeString = "" + "" + "]>&xxe;"; // String xxeString = "test@test.com"; String servletResponse = doMockPost(xxeString.getBytes(), csrfToken, 302); log.debug("Servlet Response: " + servletResponse); assertTrue(servletResponse.contains("Marsellus Wallace's Key")); assertFalse(servletResponse.contains("You must be getting funky")); } catch (Exception e) { log.fatal("Could not Complete: " + e.toString()); fail("Could not Complete: " + e.toString()); } } @Test public void testLevelWhenUnsafeLevelsAreDisabled() { Setter.closeAllModules(applicationRoot); Setter.openAllModules(applicationRoot, false); try { // Sign in as Normal User log.debug("Signing in as " + TEST_USERNAME + " Through LoginServlet"); TestProperties.loginDoPost( log, request, response, TEST_USERNAME, TEST_USERNAME, null, LANGUAGE_CODE); log.debug("Login Servlet Complete, Getting CSRF Token"); String csrfToken = response.getCookie("token").getValue(); assertFalse(csrfToken.isEmpty()); request.setCookies(response.getCookies()); Properties prop = new Properties(); try (InputStream xxe_input = new FileInputStream( System.getProperty("user.dir") + "/src/main/resources/fileSystemKeys.properties")) { prop.load(xxe_input); } catch (IOException e) { log.error("Could not load properties file: " + e.toString()); throw new RuntimeException(e); } String errorBase = "Missing property :"; String filename = prop.getProperty("xxe.lesson.file"); if (filename == null) { throw new RuntimeException(errorBase + "xxe.lesson.file"); } String xxeString = "" + "" + "]>&xxe;"; // String xxeString = "test@test.com"; String servletResponse = doMockPost(xxeString.getBytes(), csrfToken, 302); log.debug("Servlet Response: " + servletResponse); assertFalse(servletResponse.contains("Marsellus Wallace's Key")); assertTrue(servletResponse.contains(errors.getString("error.notOpen"))); } catch (Exception e) { log.fatal("Could not Complete: " + e.toString()); fail("Could not Complete: " + e.toString()); } } }