Skip to content

Commit 5daf558

Browse files
authored
fix: ensure themes stylesheets pattern is relative to context root (#22902)
* fix: ensure themes stylesheets pattern is relative to context root Aura and Lumo stylesheets are loaded by the servelt container so they should not be potentially prefixed by the Vaadin servlet URL mapping. Fixes #22899 * fix test * Add tests
1 parent 72c04b7 commit 5daf558

File tree

11 files changed

+308
-5
lines changed

11 files changed

+308
-5
lines changed

flow-server/src/main/java/com/vaadin/flow/server/HandlerHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,14 @@ public String getIdentifier() {
157157
resources.add("/" + PwaConfiguration.DEFAULT_ICON);
158158
resources.add("/" + FrontendUtils.DEFAULT_STYLES_CSS);
159159
resources.add("/themes/**");
160-
resources.add("/aura/**");
161-
resources.add("/lumo/**");
162160
resources.add("/assets/**");
163161
resources.addAll(getIconVariants(PwaConfiguration.DEFAULT_ICON));
164162
publicResources = resources.toArray(new String[resources.size()]);
165163

166164
// These are always in the root of the app, not inside any url mapping
167165
List<String> rootResources = new ArrayList<>();
166+
rootResources.add("/aura/**");
167+
rootResources.add("/lumo/**");
168168
rootResources.add("/favicon.ico");
169169
publicResourcesRoot = rootResources
170170
.toArray(new String[rootResources.size()]);

flow-server/src/test/java/com/vaadin/flow/server/HandlerHelperTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,15 +436,14 @@ public void publicResources() {
436436
expected.add("/icons/icon-1136x640.png");
437437
expected.add("/styles.css");
438438
expected.add("/themes/**");
439-
expected.add("/aura/**");
440-
expected.add("/lumo/**");
441439
expected.add("/assets/**");
442440

443441
Set<String> actual = new HashSet<>();
444442
Collections.addAll(actual, HandlerHelper.getPublicResources());
445443
Assert.assertEquals(expected, actual);
446444

447-
Set<String> expectedRoot = Set.of("/favicon.ico");
445+
Set<String> expectedRoot = Set.of("/favicon.ico", "/aura/**",
446+
"/lumo/**");
448447

449448
Set<String> actualRoot = new HashSet<>();
450449
Collections.addAll(actualRoot, HandlerHelper.getPublicResourcesRoot());

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@
316316
<module>test-spring-security-flow-standalone-routepathaccesschecker</module>
317317
<module>test-spring-security-flow-routepathaccesschecker</module>
318318
<module>test-spring-security-flow-themes-contextpath</module>
319+
<module>test-spring-security-flow-themes-urlmapping</module>
319320

320321
<module>test-spring-boot-only-prepare</module>
321322
<module>test-spring-white-list</module>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" 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">
3+
<modelVersion>4.0.0</modelVersion>
4+
<parent>
5+
<groupId>com.vaadin</groupId>
6+
<artifactId>vaadin-spring-tests</artifactId>
7+
<version>25.0-SNAPSHOT</version>
8+
</parent>
9+
<artifactId>test-spring-security-flow-themes-urlmapping</artifactId>
10+
<packaging>jar</packaging>
11+
<name>Integration tests for Vaadin Spring Security and Theme Loading With Vaadin URL mapping</name>
12+
<properties>
13+
<maven.deploy.skip>true</maven.deploy.skip>
14+
</properties>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>com.vaadin</groupId>
19+
<artifactId>vaadin-spring</artifactId>
20+
<version>${project.version}</version>
21+
</dependency>
22+
<dependency>
23+
<groupId>com.vaadin</groupId>
24+
<artifactId>vaadin-dev-server</artifactId>
25+
<version>${project.version}</version>
26+
</dependency>
27+
<dependency>
28+
<groupId>com.vaadin</groupId>
29+
<artifactId>test-aura</artifactId>
30+
<version>${project.version}</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>com.vaadin</groupId>
34+
<artifactId>test-lumo-theme</artifactId>
35+
<version>${project.version}</version>
36+
</dependency>
37+
<dependency>
38+
<groupId>com.vaadin</groupId>
39+
<artifactId>vaadin-test-spring-helpers</artifactId>
40+
<version>${project.version}</version>
41+
</dependency>
42+
<dependency>
43+
<groupId>com.vaadin</groupId>
44+
<artifactId>vaadin-test-spring-helpers</artifactId>
45+
<version>${project.version}</version>
46+
<type>test-jar</type>
47+
<scope>test</scope>
48+
</dependency>
49+
<dependency>
50+
<groupId>org.springframework.boot</groupId>
51+
<artifactId>spring-boot-starter-webmvc</artifactId>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.springframework.boot</groupId>
55+
<artifactId>spring-boot-devtools</artifactId>
56+
</dependency>
57+
<dependency>
58+
<groupId>org.springframework.boot</groupId>
59+
<artifactId>spring-boot-starter-security</artifactId>
60+
</dependency>
61+
</dependencies>
62+
63+
<build>
64+
<defaultGoal>spring-boot:run</defaultGoal>
65+
<pluginManagement>
66+
<plugins>
67+
<plugin>
68+
<groupId>org.springframework.boot</groupId>
69+
<artifactId>spring-boot-maven-plugin</artifactId>
70+
<version>${spring.boot.version}</version>
71+
</plugin>
72+
</plugins>
73+
</pluginManagement>
74+
75+
<plugins>
76+
<plugin>
77+
<groupId>com.vaadin</groupId>
78+
<artifactId>flow-maven-plugin</artifactId>
79+
<version>${project.version}</version>
80+
<executions>
81+
<execution>
82+
<goals>
83+
<goal>prepare-frontend</goal>
84+
<goal>build-frontend</goal>
85+
</goals>
86+
</execution>
87+
</executions>
88+
</plugin>
89+
<plugin>
90+
<groupId>org.springframework.boot</groupId>
91+
<artifactId>spring-boot-maven-plugin</artifactId>
92+
<configuration>
93+
<jvmArguments>-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=18888</jvmArguments>
94+
</configuration>
95+
<executions>
96+
<!-- start and stop application when running
97+
integration tests -->
98+
<execution>
99+
<id>pre-integration-test</id>
100+
<goals>
101+
<goal>start</goal>
102+
</goals>
103+
</execution>
104+
<execution>
105+
<id>post-integration-test</id>
106+
<goals>
107+
<goal>stop</goal>
108+
</goals>
109+
</execution>
110+
</executions>
111+
</plugin>
112+
</plugins>
113+
</build>
114+
115+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2000-2025 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+
package com.vaadin.flow.spring.flowthemessecuritycontextpath;
17+
18+
import org.springframework.boot.SpringApplication;
19+
import org.springframework.boot.autoconfigure.SpringBootApplication;
20+
21+
@SpringBootApplication
22+
public class Application {
23+
24+
public static void main(String[] args) {
25+
SpringApplication.run(Application.class, args);
26+
}
27+
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2000-2025 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+
package com.vaadin.flow.spring.flowthemessecuritycontextpath;
17+
18+
import com.vaadin.flow.component.dependency.StyleSheet;
19+
import com.vaadin.flow.component.page.AppShellConfigurator;
20+
21+
@StyleSheet("context://aura/fake-aura.css")
22+
@StyleSheet("context://lumo/fake-lumo.css")
23+
public class Configurator implements AppShellConfigurator {
24+
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2000-2025 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+
package com.vaadin.flow.spring.flowthemessecuritycontextpath;
17+
18+
import com.vaadin.flow.component.html.Div;
19+
import com.vaadin.flow.router.Route;
20+
import com.vaadin.flow.server.auth.AnonymousAllowed;
21+
22+
@Route("")
23+
@AnonymousAllowed
24+
public class PublicView extends Div {
25+
public PublicView() {
26+
setText("This is the public view for testing theme loading using @StyleSheet in secure environment with context path");
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2000-2025 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+
package com.vaadin.flow.spring.flowthemessecuritycontextpath;
17+
18+
import org.springframework.context.annotation.Bean;
19+
import org.springframework.context.annotation.Configuration;
20+
import org.springframework.context.annotation.Profile;
21+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
22+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
23+
import org.springframework.security.web.SecurityFilterChain;
24+
25+
import static com.vaadin.flow.spring.security.VaadinSecurityConfigurer.vaadin;
26+
27+
@EnableWebSecurity
28+
@Configuration
29+
@Profile("default")
30+
public class SecurityConfig {
31+
32+
@Bean
33+
SecurityFilterChain vaadinSecurityFilterChain(HttpSecurity http) {
34+
http.with(vaadin(), cfg -> {
35+
});
36+
return http.build();
37+
}
38+
39+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
server.port=8888
2+
logging.level.org.springframework.security=INFO
3+
server.servlet.session.persistent=false
4+
vaadin.frontend.hotdeploy=true
5+
vaadin.url-mapping=/ui/*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2000-2025 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+
package com.vaadin.flow.spring.flowthemessecuritycontextpath;
17+
18+
import org.junit.Assert;
19+
import org.junit.Test;
20+
21+
import com.vaadin.flow.spring.test.AbstractSpringTest;
22+
23+
public class AppViewIT extends AbstractSpringTest {
24+
25+
@Override
26+
protected String getRootURL() {
27+
return super.getRootURL() + "/ui";
28+
}
29+
30+
@Override
31+
protected String getTestPath() {
32+
return "";
33+
}
34+
35+
@Test
36+
public void stylesheet_auraThemeImport_importedWithNoExtraSecurityConfig() {
37+
open("");
38+
39+
// Verify that the Aura theme stylesheet from @StyleSheet has been
40+
// applied
41+
// by checking that the CSS custom property is present on :root
42+
String auraLoaded = (String) executeScript(
43+
"return getComputedStyle(document.documentElement).getPropertyValue('--fake-aura-theme-loaded').trim() ");
44+
Assert.assertEquals(
45+
"Expected :root --fake-aura-theme-loaded custom property to be set by aura/fake-aura.css",
46+
"1", auraLoaded);
47+
}
48+
49+
@Test
50+
public void stylesheet_lumoThemeImport_importedWithNoExtraSecurityConfig() {
51+
open("");
52+
53+
// Verify that the Lumo theme stylesheet from @StyleSheet has been
54+
// applied
55+
// by checking that the CSS custom property is present on :root
56+
String lumoLoaded = (String) executeScript(
57+
"return getComputedStyle(document.documentElement).getPropertyValue('--fake-lumo-theme-loaded').trim() ");
58+
Assert.assertEquals(
59+
"Expected :root --fake-lumo-theme-loaded custom property to be set by lumo/fake-lumo.css",
60+
"1", lumoLoaded);
61+
}
62+
}

0 commit comments

Comments
 (0)