diff --git a/flow-tests/pom.xml b/flow-tests/pom.xml index 56394233615..f267147a190 100644 --- a/flow-tests/pom.xml +++ b/flow-tests/pom.xml @@ -335,6 +335,8 @@ test-ccdm/pom-production.xml test-ccdm-flow-navigation test-ccdm-flow-navigation/pom-production.xml + test-fusion-csrf + test-fusion-csrf-context test-root-context diff --git a/flow-tests/test-fusion-csrf-context/.gitignore b/flow-tests/test-fusion-csrf-context/.gitignore new file mode 100644 index 00000000000..b123cfef890 --- /dev/null +++ b/flow-tests/test-fusion-csrf-context/.gitignore @@ -0,0 +1,3 @@ + +# / +frontend diff --git a/flow-tests/test-fusion-csrf-context/pom.xml b/flow-tests/test-fusion-csrf-context/pom.xml new file mode 100644 index 00000000000..d1d66b5e0cb --- /dev/null +++ b/flow-tests/test-fusion-csrf-context/pom.xml @@ -0,0 +1,151 @@ + + + + com.vaadin + flow-tests + 9.0-SNAPSHOT + + 4.0.0 + + test-fusion-csrf-context + Fusion CSRF tests with custom context path + + For https://github.com/vaadin/fusion/issues/105. + It verifies that the csrf cookie is added to correct path + when first open a sub view. + Note, the test needs to be in a separate module because + it needs to open a sub view first, put the test into another + module cannot gurantee this. + + 9.0-SNAPSHOT + war + + + true + + + + + + com.vaadin + fusion-endpoint + ${project.version} + + + com.vaadin + vaadin-dev-server + ${project.version} + + + com.vaadin + test-fusion-csrf + ${project.version} + frontend + + + com.vaadin + test-fusion-csrf + ${project.version} + test-jar + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack + generate-sources + + unpack + + + + + com.vaadin + test-fusion-csrf + ${project.version} + frontend + ${project.basedir}/frontend + + + + + + + + + org.eclipse.jetty + jetty-maven-plugin + + + + + vaadin.reuseDevServer + false + + + + /foo + + + + + com.vaadin + flow-maven-plugin + + false + + + + + + + local-run + + + !test.use.hub + + + + + + com.lazerycode.selenium + driver-binary-downloader-maven-plugin + + + ${driver.binary.downloader.maven.plugin.version} + + + true + + + ${project.rootdir}/driver + + + ${project.rootdir}/driver_zips + + + ${project.rootdir}/drivers.xml + + + + + pre-integration-test + + selenium + + + + + + + + + diff --git a/flow-tests/test-fusion-csrf-context/src/main/java/com/vaadin/fusion/csrftest/MyServlet.java b/flow-tests/test-fusion-csrf-context/src/main/java/com/vaadin/fusion/csrftest/MyServlet.java new file mode 100644 index 00000000000..4b44872e569 --- /dev/null +++ b/flow-tests/test-fusion-csrf-context/src/main/java/com/vaadin/fusion/csrftest/MyServlet.java @@ -0,0 +1,10 @@ +package com.vaadin.fusion.csrftest; + +import javax.servlet.annotation.WebServlet; + +import com.vaadin.flow.server.VaadinServlet; + +@WebServlet("/*") +public class MyServlet extends VaadinServlet { + +} diff --git a/flow-tests/test-fusion-csrf-context/src/test/java/com/vaadin/fusion/csrftest/CsrfCookieWithTrailingSlashAndCustomContextIT.java b/flow-tests/test-fusion-csrf-context/src/test/java/com/vaadin/fusion/csrftest/CsrfCookieWithTrailingSlashAndCustomContextIT.java new file mode 100644 index 00000000000..80f3a8f1f5e --- /dev/null +++ b/flow-tests/test-fusion-csrf-context/src/test/java/com/vaadin/fusion/csrftest/CsrfCookieWithTrailingSlashAndCustomContextIT.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2021 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.fusion.csrftest; + +public class CsrfCookieWithTrailingSlashAndCustomContextIT + extends CsrfCookieWithTrailingSlashIT { + @Override + protected String getContextPath() { + return "/foo"; + } +} diff --git a/flow-tests/test-fusion-csrf/frontend/index.html b/flow-tests/test-fusion-csrf/frontend/index.html new file mode 100644 index 00000000000..caa0ebe667e --- /dev/null +++ b/flow-tests/test-fusion-csrf/frontend/index.html @@ -0,0 +1,24 @@ + + + + + + fusion-csrf + + + + + +
+ + diff --git a/flow-tests/test-fusion-csrf/frontend/index.ts b/flow-tests/test-fusion-csrf/frontend/index.ts new file mode 100644 index 00000000000..276df86dfa0 --- /dev/null +++ b/flow-tests/test-fusion-csrf/frontend/index.ts @@ -0,0 +1,17 @@ +import { Router, Route } from '@vaadin/router'; +import './views/helloworld/hello-world-view'; + +export const router = new Router(document.querySelector('#outlet')); + +export const routes: Route[] = [ + // place routes below (more info https://vaadin.com/docs/latest/fusion/routing/overview) + { + path: '', + component: 'hello-world-view', + }, + { + path: 'hello', + component: 'hello-world-view', + } +]; +router.setRoutes(routes); \ No newline at end of file diff --git a/flow-tests/test-fusion-csrf/frontend/views/helloworld/hello-world-view.ts b/flow-tests/test-fusion-csrf/frontend/views/helloworld/hello-world-view.ts new file mode 100644 index 00000000000..0aa0a2bd324 --- /dev/null +++ b/flow-tests/test-fusion-csrf/frontend/views/helloworld/hello-world-view.ts @@ -0,0 +1,11 @@ +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +@customElement('hello-world-view') +export class HelloWorldView extends LitElement { + render() { + return html` +
HelloWorldView
+ `; + } +} diff --git a/flow-tests/test-fusion-csrf/pom.xml b/flow-tests/test-fusion-csrf/pom.xml new file mode 100644 index 00000000000..018e32b142a --- /dev/null +++ b/flow-tests/test-fusion-csrf/pom.xml @@ -0,0 +1,133 @@ + + + + com.vaadin + flow-tests + 9.0-SNAPSHOT + + 4.0.0 + + test-fusion-csrf + Fusion CSRF tests (dev mode) + + For https://github.com/vaadin/fusion/issues/105. + It verifies that the csrf cookie is added to correct path + when first open a sub view. + Note, the test needs to be in a separate module because + it needs to open a sub view first, put the test into another + module cannot gurantee this. + + 9.0-SNAPSHOT + war + + + true + + + + + + com.vaadin + fusion-endpoint + ${project.version} + + + com.vaadin + vaadin-dev-server + ${project.version} + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + + test-jar + + + + package-frontend-folder + + jar + + + frontend + ${project.basedir}/frontend + + + + + + + org.eclipse.jetty + jetty-maven-plugin + + + + + vaadin.reuseDevServer + false + + + + + + com.vaadin + flow-maven-plugin + + false + + + + + + + local-run + + + !test.use.hub + + + + + + com.lazerycode.selenium + driver-binary-downloader-maven-plugin + + + ${driver.binary.downloader.maven.plugin.version} + + + true + + + ${project.rootdir}/driver + + + ${project.rootdir}/driver_zips + + + ${project.rootdir}/drivers.xml + + + + + pre-integration-test + + selenium + + + + + + + + + diff --git a/flow-tests/test-fusion-csrf/src/main/java/com/vaadin/fusion/csrftest/MyServlet.java b/flow-tests/test-fusion-csrf/src/main/java/com/vaadin/fusion/csrftest/MyServlet.java new file mode 100644 index 00000000000..4b44872e569 --- /dev/null +++ b/flow-tests/test-fusion-csrf/src/main/java/com/vaadin/fusion/csrftest/MyServlet.java @@ -0,0 +1,10 @@ +package com.vaadin.fusion.csrftest; + +import javax.servlet.annotation.WebServlet; + +import com.vaadin.flow.server.VaadinServlet; + +@WebServlet("/*") +public class MyServlet extends VaadinServlet { + +} diff --git a/flow-tests/test-fusion-csrf/src/test/java/com/vaadin/fusion/csrftest/CsrfCookieWithTrailingSlashIT.java b/flow-tests/test-fusion-csrf/src/test/java/com/vaadin/fusion/csrftest/CsrfCookieWithTrailingSlashIT.java new file mode 100644 index 00000000000..f23574c126b --- /dev/null +++ b/flow-tests/test-fusion-csrf/src/test/java/com/vaadin/fusion/csrftest/CsrfCookieWithTrailingSlashIT.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2021 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.fusion.csrftest; + +import java.io.IOException; +import java.net.CookieHandler; +import java.net.CookieManager; +import java.net.CookieStore; +import java.net.HttpCookie; +import java.net.URL; +import java.net.URLConnection; + +import com.vaadin.flow.testutil.ChromeBrowserTest; + +import org.junit.Assert; +import org.junit.Test; + +public class CsrfCookieWithTrailingSlashIT extends ChromeBrowserTest { + @Test + // https://github.com/vaadin/fusion/issues/105 + public void should_registerCsrfCookieToContextRoot_whenRequestFromSubViewAndUrlHasTrailingSlash() + throws IOException { + CookieManager cookieManager = new CookieManager(); + CookieHandler.setDefault(cookieManager); + + open(); + + URL url = new URL(getTestURL()); + URLConnection urlConnection = url.openConnection(); + urlConnection.getContent(); + // Get CookieStore + CookieStore cookieStore = cookieManager.getCookieStore(); + + HttpCookie csrfCookie = cookieStore.getCookies().stream() + .filter(cookie -> "csrfToken".equals(cookie.getName())) + .findFirst().get(); + Assert.assertEquals(getContextPath(), csrfCookie.getPath()); + } + + @Override + protected String getTestPath() { + return getContextPath() + ("/".equals(getContextPath()) ? "" : "/") + + "hello/"; + } + + protected String getContextPath() { + return "/"; + } +} diff --git a/fusion-endpoint/src/main/java/com/vaadin/fusion/auth/CsrfIndexHtmlRequestListener.java b/fusion-endpoint/src/main/java/com/vaadin/fusion/auth/CsrfIndexHtmlRequestListener.java index b5fde0df017..3d5cf133b38 100644 --- a/fusion-endpoint/src/main/java/com/vaadin/fusion/auth/CsrfIndexHtmlRequestListener.java +++ b/fusion-endpoint/src/main/java/com/vaadin/fusion/auth/CsrfIndexHtmlRequestListener.java @@ -66,7 +66,11 @@ private void ensureCsrfTokenCookieIsSet(VaadinRequest request, Cookie csrfCookie = new Cookie(ApplicationConstants.CSRF_TOKEN, csrfToken); csrfCookie.setSecure(request.isSecure()); - csrfCookie.setPath(request.getContextPath()); + String path = request.getContextPath(); + if (path == null || path.isEmpty()) { + path = "/"; + } + csrfCookie.setPath(path); csrfCookie.setHttpOnly(false); response.addCookie(csrfCookie); }