Mercurial > stress-tester
changeset 445:cf6662b69c07
HttpCsrfFilter - Store strategy
author | Devel 1 |
---|---|
date | Mon, 31 Jul 2017 09:19:32 +0200 |
parents | 6002d2c3f9d1 |
children | a6697ffb881c |
files | stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilterExtractorTransformer.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilterInjectorTransformer.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilterStoreTransformer.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpCsrfFilterTest.java |
diffstat | 5 files changed, 152 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilter.java Fri Jul 28 15:54:52 2017 +0200 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilter.java Mon Jul 31 09:19:32 2017 +0200 @@ -10,6 +10,7 @@ import com.passus.config.schema.KeyNameVaryListNodeDefinition; import com.passus.config.schema.NodeDefinition; import com.passus.config.schema.NodeDefinitionCreator; +import com.passus.config.schema.ValueNodeDefinition; import com.passus.data.ByteString; import com.passus.net.http.HttpCookie; import com.passus.net.http.HttpMessage; @@ -112,38 +113,48 @@ public static abstract class Store { - public abstract void save(ByteString token); + public abstract void save(ParametersBag session, ByteString token); - public abstract ByteString load(); + public abstract ByteString load(ParametersBag session); + + protected Object get(ParametersBag session) { + return session != null ? session.get(SESSION_KEY) : null; + } + + protected void put(ParametersBag session, Object store) { + session.set(SESSION_KEY, store); + } } public static final class QueueStore extends Store { - private final Queue<ByteString> tokens = new LinkedList<>(); - @Override - public void save(ByteString token) { + public void save(ParametersBag session, ByteString token) { + Queue<ByteString> tokens = (Queue<ByteString>) get(session); + if (tokens == null) { + tokens = new LinkedList<>(); + put(session, tokens); + } tokens.add(token); } @Override - public ByteString load() { - return tokens.poll(); + public ByteString load(ParametersBag session) { + Queue<ByteString> tokens = (Queue<ByteString>) get(session); + return tokens == null ? null : tokens.poll(); } } public static final class SingleTokenStore extends Store { - private ByteString token; - @Override - public void save(ByteString token) { - this.token = token; + public void save(ParametersBag session, ByteString token) { + put(session, token); } @Override - public ByteString load() { - return token; + public ByteString load(ParametersBag session) { + return (ByteString) get(session); } } @@ -157,6 +168,8 @@ private final List<Injector> injectors = new ArrayList<>(); + private Store tokenStore = new QueueStore(); + public HttpCsrfFilter() { } @@ -203,10 +216,19 @@ this.injectors.remove(injector); } + public Store getTokenStore() { + return tokenStore; + } + + public void setTokenStore(Store tokenStore) { + this.tokenStore = tokenStore; + } + @Override public void configure(Configuration cfg) { setExtractors((List<Extractor>) cfg.get("extract", Collections.EMPTY_LIST)); setInjectors((List<Injector>) cfg.get("inject", Collections.EMPTY_LIST)); + setTokenStore((Store) cfg.get("store", tokenStore)); } @Override @@ -214,10 +236,8 @@ if (req != null) { ParametersBag session = context.scopes().getSession(req); if (session != null) { - Store store = (Store) session.get(SESSION_KEY); - if (store != null) { - ByteString token = store.load(); - + ByteString token = tokenStore.load(session); + if (token != null) { for (Injector injector : injectors) { injector.inject(req, token); } @@ -242,14 +262,7 @@ if (token != null) { ParametersBag session = context.scopes().getSession(resp); if (session != null) { - Store store = (Store) session.get(SESSION_KEY); - - if (store == null) { - store = new QueueStore(); - session.set(SESSION_KEY, store); - } - - store.save(token); + tokenStore.save(session, token); } } } @@ -275,9 +288,12 @@ .setNodeTransformer(new HttpCsrfFilterInjectorTransformer()) .add("header", valueDef().addValidator(HeaderNameValidator.INSTANCE)); + ValueNodeDefinition storeDef = valueDef().setTransformer(new HttpCsrfFilterStoreTransformer()); + return mapDef( tupleDef("extract", extractorsDef), - tupleDef("inject", injectorsDef) + tupleDef("inject", injectorsDef), + tupleDef("store", storeDef).setRequired(false) ); }
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilterExtractorTransformer.java Fri Jul 28 15:54:52 2017 +0200 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilterExtractorTransformer.java Mon Jul 31 09:19:32 2017 +0200 @@ -19,7 +19,7 @@ * * @author Mirosław Hawrot */ -public class HttpCsrfFilterExtractorTransformer implements NodeTransformer { +class HttpCsrfFilterExtractorTransformer implements NodeTransformer { private Extractor createNameExtractor(CTupleNode tuple, Errors errors, Class<? extends Extractor> clazz) { if (validateType(tuple.getNode(), NodeType.VALUE, errors)) {
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilterInjectorTransformer.java Fri Jul 28 15:54:52 2017 +0200 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilterInjectorTransformer.java Mon Jul 31 09:19:32 2017 +0200 @@ -18,7 +18,7 @@ * * @author Mirosław Hawrot */ -public class HttpCsrfFilterInjectorTransformer implements NodeTransformer { +class HttpCsrfFilterInjectorTransformer implements NodeTransformer { private Injector createNameExtractor(CTupleNode tuple, Errors errors, Class<? extends Injector> clazz) { if (validateType(tuple.getNode(), NodeType.VALUE, errors)) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpCsrfFilterStoreTransformer.java Mon Jul 31 09:19:32 2017 +0200 @@ -0,0 +1,33 @@ +package com.passus.st.client.http.filter; + +import com.passus.commons.ConversionException; +import com.passus.config.ValueTransformer; + +/** + * + * @author mikolaj.podbielski + */ +class HttpCsrfFilterStoreTransformer implements ValueTransformer { + + @Override + public Object transform(Object obj) throws ConversionException { + if (obj instanceof String) { + String s = (String) obj; + switch (s) { + case "queue": + return new HttpCsrfFilter.QueueStore(); + case "single": + return new HttpCsrfFilter.SingleTokenStore(); + default: + throw new ConversionException("Unknown token store type: " + s); + } + } + throw new ConversionException("Invalid token store type."); + } + + @Override + public Object reverseTransform(Object obj) throws ConversionException { + throw new UnsupportedOperationException("Not supported yet."); + } + +}
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpCsrfFilterTest.java Fri Jul 28 15:54:52 2017 +0200 +++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpCsrfFilterTest.java Mon Jul 31 09:19:32 2017 +0200 @@ -1,11 +1,13 @@ package com.passus.st.client.http.filter; import com.passus.config.validation.Errors; +import com.passus.data.ByteString; import com.passus.net.http.HttpMessage; import com.passus.net.http.HttpRequest; import com.passus.net.http.HttpRequestBuilder; import com.passus.net.http.HttpResponse; import com.passus.net.http.HttpResponseBuilder; +import com.passus.st.ParametersBag; import static com.passus.st.client.http.HttpConsts.TAG_SESSION_ID; import com.passus.st.client.http.HttpFlowContext; import com.passus.st.client.http.HttpScopes; @@ -14,6 +16,9 @@ import com.passus.st.client.http.filter.HttpCsrfFilter.HeaderExtractor; import com.passus.st.client.http.filter.HttpCsrfFilter.HeaderInjector; import com.passus.st.client.http.filter.HttpCsrfFilter.Injector; +import com.passus.st.client.http.filter.HttpCsrfFilter.QueueStore; +import com.passus.st.client.http.filter.HttpCsrfFilter.SingleTokenStore; +import com.passus.st.client.http.filter.HttpCsrfFilter.Store; import com.passus.st.emitter.SessionInfo; import java.util.List; import static org.testng.AssertJUnit.assertEquals; @@ -31,7 +36,69 @@ } @Test - public void testFilter_CookieExtractorHeaderInjector() throws Exception { + public void testCookieExtractor() { + CookieExtractor extractor = new CookieExtractor("x_csrf_token"); + HttpResponse resp = HttpResponseBuilder.ok() + .cookie("x_csrf_token", "value1") + .build(); + + ByteString value = extractor.extract(resp); + assertEquals("value1", value.toString()); + } + + @Test + public void testHeaderExtractor() { + HeaderExtractor extractor = new HeaderExtractor("x-csrf-token"); + HttpResponse resp = HttpResponseBuilder.ok() + .header("x-csrf-token", "value1") + .build(); + + ByteString value = extractor.extract(resp); + assertEquals("value1", value.toString()); + } + + @Test + public void testHeaderInjector() { + HeaderInjector injector = new HeaderInjector("x-csrf-token"); + HttpRequest req = HttpRequestBuilder.get("http://test/test1") + .header("x-csrf-token", "oldValue") + .build(); + + injector.inject(req, ByteString.create("newValue")); + assertEquals("newValue", req.getHeaders().get("x-csrf-token").toString()); + } + + @Test + public void testQueueStore() { + QueueStore store = new QueueStore(); + ParametersBag session = new ParametersBag(); + + assertTrue(store.load(session) == null); + + store.save(session, ByteString.create("token1")); + store.save(session, ByteString.create("token2")); + assertEquals("token1", store.load(session).toString()); + assertEquals("token2", store.load(session).toString()); + assertTrue(store.load(session) == null); + } + + @Test + public void testSingleTokenStore() { + SingleTokenStore store = new SingleTokenStore(); + ParametersBag session = new ParametersBag(); + + assertTrue(store.load(session) == null); + + store.save(session, ByteString.create("token1")); + assertEquals("token1", store.load(session).toString()); + assertEquals("token1", store.load(session).toString()); + + store.save(session, ByteString.create("token2")); + assertEquals("token2", store.load(session).toString()); + } + + @Test + public void testFilter_CookieExtractorHeaderInjectorQueueStore() throws Exception { HttpRequest req1 = HttpRequestBuilder.get("http://test/test1") .header("x-csrf-token", "token") .build(); @@ -58,6 +125,7 @@ HttpCsrfFilter filter = new HttpCsrfFilter(); filter.addExtractor(cookieExtractor); filter.addInjector(headerInjector); + filter.setTokenStore(new QueueStore()); filter.filterOutbound(req1, null, context); filter.filterInbound(null, resp1, context); @@ -75,7 +143,8 @@ + " header: \"csrf-header\"\n" + " cookie: \"csrf-cookie\"\n" + " inject:\n" - + " header: \"csrf-header-inject\"\n"; + + " header: \"csrf-header-inject\"\n" + + " store: single\n"; Errors errors = new Errors(); List<HttpFilter> filters = HttpFiltersConfigurator.getFilters(filterConfig, errors); @@ -85,6 +154,10 @@ assertTrue(filters.get(0) instanceof HttpCsrfFilter); HttpCsrfFilter filter = (HttpCsrfFilter) filters.get(0); + + Store tokenStore = filter.getTokenStore(); + assertTrue(tokenStore instanceof SingleTokenStore); + List<Extractor> extractors = filter.getExtractors(); List<Injector> injectors = filter.getInjectors();