Mercurial > stress-tester
changeset 477:ee228e860ea2
ST-60 in progress
author | Devel 1 |
---|---|
date | Tue, 08 Aug 2017 09:33:22 +0200 |
parents | a49913dd5064 |
children | ce8d1a1cda94 |
files | stress-tester/pom.xml stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFormExtractor.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpCsrfFormExtractorTest.java |
diffstat | 3 files changed, 237 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/stress-tester/pom.xml Tue Aug 08 09:30:02 2017 +0200 +++ b/stress-tester/pom.xml Tue Aug 08 09:33:22 2017 +0200 @@ -126,6 +126,12 @@ </dependency> <dependency> + <groupId>org.jsoup</groupId> + <artifactId>jsoup</artifactId> + <version>1.9.2</version> + </dependency> + + <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.9.10</version>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFormExtractor.java Tue Aug 08 09:33:22 2017 +0200 @@ -0,0 +1,134 @@ +package com.passus.st.client.http.filter; + +import java.util.ArrayList; +import java.util.List; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.FormElement; +import org.jsoup.select.Elements; + +/** + * + * @author mikolaj.podbielski + */ +public class HttpCsrfFormExtractor { + + private static final String TAG_FORM = "form"; + + private static final String FORM_START = "<form"; + private static final String FORM_END = "</form>"; + + private static final String ATTR_ACTION = "action"; + private static final String ATTR_METHOD = "method"; + private static final String ATTR_NAME = "name"; + private static final String ATTR_VALUE = "value"; + + // TODO: obsługiwać '< form' itp + static List<FormBoundary> scan(String document) { + document = document.toLowerCase(); + List<FormBoundary> result = new ArrayList<>(); + + int startPos = 0; + while (true) { + startPos = document.indexOf(FORM_START, startPos); + if (startPos < 0) { + break; + } + + int endPos = document.indexOf(FORM_END, startPos); + if (endPos < 0) { + break; + } + endPos += FORM_END.length(); + + result.add(new FormBoundary(startPos, endPos)); + startPos = endPos; + } + + return result; + } + + static TokenEntry extract(String formString, String inputId, String inputName) { + Document root = Jsoup.parse(formString); + Elements forms = root.getElementsByTag(TAG_FORM); + if (forms.size() != 1) { + throw new IllegalArgumentException("Given fragment is not a form."); + } + FormElement form = (FormElement) forms.get(0); + Elements inputs = form.elements(); + + Element tokenInput = null; + for (Element input : inputs) { + if (!input.attr("type").equals("hidden")) { + continue; + } + if (inputId != null) { + if (!inputId.equals(input.id())) { + continue; + } + } + if (inputName != null) { + if (!inputName.equals(input.attr("name"))) { + continue; + } + } + tokenInput = input; + break; + } + + if (tokenInput == null) { + return null; + } + + String action = form.attr(ATTR_ACTION); + String method = form.attr(ATTR_METHOD); + String name = form.attr(ATTR_NAME); + String value = tokenInput.attr(ATTR_VALUE); + return new TokenEntry(action, method, name, value); + } + + public static List<TokenEntry> extractAll(String document, String inputId, String inputName) { + List<FormBoundary> forms = scan(document); + List<TokenEntry> result = new ArrayList<>(forms.size()); + for (FormBoundary form : forms) { + TokenEntry entry = extract(document.substring(form.start, form.end), inputId, inputName); + if (entry != null) { + result.add(entry); + } + } + return result; + } + + public static class FormBoundary { + + int start; + int end; + + public FormBoundary(int start, int end) { + this.start = start; + this.end = end; + } + } + + public static class TokenEntry { + + final String action; + final String method; + final String name; + final String value; + + public TokenEntry(String action, String method, String name, String value) { + this.action = action; + this.method = method; + this.name = name; + this.value = value; + } + + @Override + public String toString() { + return "TokenEntry{" + "action=" + action + ", method=" + method + ", name=" + name + ", value=" + value + '}'; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpCsrfFormExtractorTest.java Tue Aug 08 09:33:22 2017 +0200 @@ -0,0 +1,97 @@ +package com.passus.st.client.http.filter; + +import com.passus.commons.utils.ResourceUtils; +import com.passus.st.client.http.filter.HttpCsrfFormExtractor.TokenEntry; +import com.passus.st.client.http.filter.HttpCsrfFormExtractor.FormBoundary; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import static org.testng.AssertJUnit.*; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * + * @author mikolaj.podbielski + */ +public class HttpCsrfFormExtractorTest { + + String document; + + @BeforeClass + public void setup() throws IOException { + File file = ResourceUtils.getFile("com/passus/st/client/http/filter/form_csrf1.html"); + byte[] bytes = Files.readAllBytes(Paths.get(file.toURI())); + document = new String(bytes); + } + + @Test + public void testScan() { + List<FormBoundary> bounds = HttpCsrfFormExtractor.scan(document); + assertEquals(4, bounds.size()); + bounds.forEach((fb) -> assertTrue(fb.start < fb.end)); + assertEquals(bounds.get(1).end, bounds.get(2).start); + } + + @Test + public void testExtractFromComplexHtml() { + FormBoundary fb = HttpCsrfFormExtractor.scan(document).get(0); + String form = document.substring(fb.start, fb.end); + + // no action + TokenEntry entry = HttpCsrfFormExtractor.extract(form, "form__token", "form[_token]"); + assertEntryEquals(entry, "", "post", "form1", "token-1qwerty"); + } + + @Test + public void testExtract() { + String tag; + TokenEntry entry; + + // absolute action, no method + tag = "<form name=\"f1\" action=\"/svc/save\"><input type=\"hidden\" id=\"t_id\" name=\"t_n\" value=\"t4val\" /></form>"; + entry = HttpCsrfFormExtractor.extract(tag, "t_id", "t_n"); + assertEntryEquals(entry, "/svc/save", "", "f1", "t4val"); + + // relative action, no form name + tag = "<form action=\"save\" method=\"post\"><input type=\"hidden\" id=\"t_id\" name=\"t_n\" value=\"t4val\" /></form>"; + entry = HttpCsrfFormExtractor.extract(tag, "t_id", "t_n"); + assertEntryEquals(entry, "save", "post", "", "t4val"); + } + + @Test + public void testExtractByIdName() { + String tag = "<form>" + + "<input type=\"hidden\" value=\"t4val1\" />" + + "<input type=\"hidden\" name=\"t_n\" value=\"t4val2\" />" + + "<input type=\"hidden\" id=\"t_id\" value=\"t4val3\" />" + + "<input type=\"hidden\" id=\"t_id\" name=\"t_n\" value=\"t4val4\" />" + + "</form>"; + TokenEntry entry; + +// token by name and id + entry = HttpCsrfFormExtractor.extract(tag, "t_id", "t_n"); + assertEquals("t4val4", entry.value); + +// token by id + entry = HttpCsrfFormExtractor.extract(tag, "t_id", null); + assertEquals("t4val3", entry.value); + +// token by name + entry = HttpCsrfFormExtractor.extract(tag, null, "t_n"); + assertEquals("t4val2", entry.value); + +// token is first hidden input + entry = HttpCsrfFormExtractor.extract(tag, null, null); + assertEquals("t4val1", entry.value); + } + + private static void assertEntryEquals(TokenEntry entry, String action, String method, String name, String value) { + assertEquals(action, entry.action); + assertEquals(method, entry.method); + assertEquals(name, entry.name); + assertEquals(value, entry.value); + } +}