Skip to content

Commit d2c9e61

Browse files
fix: fix redirect URL for PUSH with websocket transport (#20666) (CP: 24.5) (#20677)
* fix: fix redirect URL for PUSH with websocket transport (#20666) When PUSH is enabled with websocket transport, the redirect URL to be used after a successfull login is not correctly computed because it is based on the PUSH servlet mapping. This change detects the situation and computes the correct URL. Fixes #20575 * fix version --------- Co-authored-by: Marco Collovati <marco@vaadin.com>
1 parent 33463c4 commit d2c9e61

File tree

8 files changed

+214
-1
lines changed

8 files changed

+214
-1
lines changed

flow-server/src/main/java/com/vaadin/flow/server/auth/NavigationAccessControl.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import com.vaadin.flow.router.NotFoundException;
3535
import com.vaadin.flow.router.RouteParameters;
3636
import com.vaadin.flow.router.internal.PathUtil;
37+
import com.vaadin.flow.server.Constants;
38+
import com.vaadin.flow.server.HandlerHelper;
3739
import com.vaadin.flow.server.VaadinRequest;
3840
import com.vaadin.flow.server.VaadinService;
3941
import com.vaadin.flow.server.VaadinServletRequest;
@@ -369,7 +371,13 @@ protected Predicate<String> getRolesChecker(VaadinRequest request) {
369371
*/
370372
protected String getRequestURL(VaadinRequest vaadinRequest) {
371373
if (vaadinRequest instanceof VaadinServletRequest httpRequest) {
372-
return httpRequest.getRequestURL().toString();
374+
String url = httpRequest.getRequestURL().toString();
375+
if (HandlerHelper.isRequestType(vaadinRequest,
376+
HandlerHelper.RequestType.PUSH)
377+
&& url.endsWith(Constants.PUSH_MAPPING)) {
378+
url = url.substring(0, url.indexOf(Constants.PUSH_MAPPING));
379+
}
380+
return url;
373381
}
374382
return "";
375383
}

flow-tests/vaadin-spring-tests/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@
324324
<module>test-mvc-without-endpoints</module>
325325

326326
<module>test-spring-security-flow</module>
327+
<module>test-spring-security-flow-websocket</module>
327328
<module>test-spring-security-webicons</module>
328329
<module>test-spring-security-webicons-urlmapping</module>
329330
<module>test-spring-security-flow-contextpath</module>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>com.vaadin</groupId>
7+
<artifactId>vaadin-spring-tests</artifactId>
8+
<version>24.5-SNAPSHOT</version>
9+
</parent>
10+
<artifactId>test-spring-security-flow-websocket</artifactId>
11+
<name>Integration tests for Vaadin Spring Security and Flow With Websocket PUSH</name>
12+
<packaging>jar</packaging>
13+
<properties>
14+
<maven.deploy.skip>true</maven.deploy.skip>
15+
</properties>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>com.vaadin</groupId>
20+
<artifactId>vaadin-spring</artifactId>
21+
<version>${project.version}</version>
22+
</dependency>
23+
<dependency>
24+
<groupId>com.vaadin</groupId>
25+
<artifactId>vaadin-dev-server</artifactId>
26+
<version>${project.version}</version>
27+
</dependency>
28+
<dependency>
29+
<groupId>org.springframework.boot</groupId>
30+
<artifactId>spring-boot-starter-web</artifactId>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.springframework.boot</groupId>
34+
<artifactId>spring-boot-devtools</artifactId>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.springframework.boot</groupId>
38+
<artifactId>spring-boot-starter-security</artifactId>
39+
</dependency>
40+
41+
<dependency>
42+
<groupId>com.vaadin</groupId>
43+
<artifactId>test-spring-security-flow</artifactId>
44+
<version>${project.version}</version>
45+
</dependency>
46+
<dependency>
47+
<groupId>com.vaadin</groupId>
48+
<artifactId>test-spring-security-flow</artifactId>
49+
<version>${project.version}</version>
50+
<type>test-jar</type>
51+
<classifier>tests</classifier>
52+
<scope>test</scope>
53+
</dependency>
54+
</dependencies>
55+
56+
<build>
57+
<defaultGoal>spring-boot:run</defaultGoal>
58+
<pluginManagement>
59+
<plugins>
60+
<plugin>
61+
<groupId>org.springframework.boot</groupId>
62+
<artifactId>spring-boot-maven-plugin</artifactId>
63+
<version>${spring.boot.version}</version>
64+
</plugin>
65+
</plugins>
66+
</pluginManagement>
67+
68+
<plugins>
69+
<plugin>
70+
<groupId>com.vaadin</groupId>
71+
<artifactId>flow-maven-plugin</artifactId>
72+
<version>${project.version}</version>
73+
<configuration>
74+
<forceProductionBuild>true</forceProductionBuild>
75+
</configuration>
76+
<executions>
77+
<execution>
78+
<goals>
79+
<goal>prepare-frontend</goal>
80+
<goal>build-frontend</goal>
81+
</goals>
82+
</execution>
83+
</executions>
84+
</plugin>
85+
<plugin>
86+
<groupId>org.springframework.boot</groupId>
87+
<artifactId>spring-boot-maven-plugin</artifactId>
88+
<configuration>
89+
<jvmArguments>
90+
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=18888
91+
</jvmArguments>
92+
</configuration>
93+
<executions>
94+
<!-- start and stop application when running
95+
integration tests -->
96+
<execution>
97+
<id>pre-integration-test</id>
98+
<goals>
99+
<goal>start</goal>
100+
</goals>
101+
</execution>
102+
<execution>
103+
<id>post-integration-test</id>
104+
<goals>
105+
<goal>stop</goal>
106+
</goals>
107+
</execution>
108+
</executions>
109+
</plugin>
110+
</plugins>
111+
</build>
112+
113+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.vaadin.flow.spring.flowsecuritywebsocket;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class Application
8+
extends com.vaadin.flow.spring.flowsecurity.Application {
9+
10+
public static void main(String[] args) {
11+
SpringApplication.run(Application.class, args);
12+
}
13+
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2000-2024 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package com.vaadin.flow.spring.flowsecuritywebsocket;
18+
19+
import org.springframework.stereotype.Component;
20+
21+
import com.vaadin.flow.router.BeforeEnterEvent;
22+
import com.vaadin.flow.router.BeforeEnterListener;
23+
import com.vaadin.flow.router.ListenerPriority;
24+
import com.vaadin.flow.server.ServiceInitEvent;
25+
import com.vaadin.flow.server.VaadinServiceInitListener;
26+
import com.vaadin.flow.shared.ui.Transport;
27+
28+
@Component
29+
public class PushWebsocketConfigurer implements VaadinServiceInitListener {
30+
31+
private final PushTransportSetter pushTransportSetter = new PushTransportSetter();
32+
33+
@Override
34+
public void serviceInit(ServiceInitEvent event) {
35+
36+
event.getSource().addUIInitListener(uiInitEvent -> {
37+
// Transport cannot be set directly in UI listener because
38+
// BootstrapHandler overrides it with @Push annotation value.
39+
uiInitEvent.getUI().addBeforeEnterListener(pushTransportSetter);
40+
});
41+
}
42+
43+
@ListenerPriority(10)
44+
private static class PushTransportSetter implements BeforeEnterListener {
45+
46+
@Override
47+
public void beforeEnter(BeforeEnterEvent event) {
48+
event.getUI().getPushConfiguration()
49+
.setTransport(Transport.WEBSOCKET);
50+
}
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
server.port=8888
2+
logging.level.org.springframework.security=TRACE
3+
logging.level.org.atmosphere=DEBUG
4+
server.servlet.session.persistent=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.vaadin.flow.spring.flowsecuritywebsocket;
2+
3+
import org.junit.Ignore;
4+
import org.junit.Test;
5+
6+
public class AppViewIT extends com.vaadin.flow.spring.flowsecurity.AppViewIT {
7+
8+
@Test
9+
@Ignore("""
10+
With WEBSOCKET transport the WS connection is closed when session
11+
is invalidated, but Flow client attempts a reconnection and
12+
re-enables heartbeat. The heartbeat ping resolves in a 403 HTTP
13+
status code because of session expiration, causing the client-side
14+
session expiration handler to redirect to the timeout page instead
15+
of the logout view, because the logout process is still ongoing.
16+
""")
17+
public void logout_via_doLogin_redirects_to_logout() {
18+
super.logout_via_doLogin_redirects_to_logout();
19+
}
20+
}

scripts/computeMatrix.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ const moduleWeights = {
102102
'flow-tests/vaadin-spring-tests/test-spring-security-flow': { pos: 5, weight: 3 },
103103
'flow-tests/vaadin-spring-tests/test-spring-security-webicons': { pos: 5, weight: 3 },
104104
'flow-tests/vaadin-spring-tests/test-spring-security-webicons-urlmapping': { pos: 5, weight: 3 },
105+
'flow-tests/vaadin-spring-tests/test-spring-security-flow-websocket': { pos: 5, weight: 3 },
105106
'flow-tests/vaadin-spring-tests/test-spring-security-flow-contextpath': { pos: 5, weight: 3 },
106107
'flow-tests/vaadin-spring-tests/test-spring-security-flow-methodsecurity': { pos: 5, weight: 3 },
107108
'flow-tests/vaadin-spring-tests/test-spring-security-flow-urlmapping': { pos: 5, weight: 3 },

0 commit comments

Comments
 (0)