Skip to content

Commit 4acee57

Browse files
committed
Add configuration for allowing http connection during development
WE2-967 Signed-off-by: Sven Mitt <svenzik@users.noreply.github.com>
1 parent 5d9cb3b commit 4acee57

7 files changed

Lines changed: 174 additions & 7 deletions

File tree

example/src/main/java/eu/webeid/example/config/SameSiteCookieConfiguration.java renamed to example/src/main/java/eu/webeid/example/config/CookieConfiguration.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@
2323
package eu.webeid.example.config;
2424

2525
import org.apache.tomcat.util.http.Rfc6265CookieProcessor;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
2627
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
28+
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
29+
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
2730
import org.springframework.context.annotation.Bean;
2831
import org.springframework.context.annotation.Configuration;
2932
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
3033

3134
@Configuration
32-
public class SameSiteCookieConfiguration implements WebMvcConfigurer {
35+
public class CookieConfiguration implements WebMvcConfigurer {
3336

3437
@Bean
3538
public TomcatContextCustomizer configureSameSiteCookies() {
@@ -39,4 +42,16 @@ public TomcatContextCustomizer configureSameSiteCookies() {
3942
context.setCookieProcessor(cookieProcessor);
4043
};
4144
}
45+
46+
@Bean
47+
@ConditionalOnExpression("'${web-eid-auth-token.validation.local-origin}'.startsWith('http:')")
48+
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> httpSessionCookieCustomizer() {
49+
return factory -> factory.addInitializers(servletContext -> servletContext.getSessionCookieConfig().setName("JSESSIONID"));
50+
}
51+
52+
@Bean
53+
@ConditionalOnExpression("'${web-eid-auth-token.validation.local-origin}'.startsWith('https:')")
54+
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> httpsSessionCookieCustomizer() {
55+
return factory -> factory.addInitializers(servletContext -> servletContext.getSessionCookieConfig().setName("__Host-JSESSIONID"));
56+
}
4257
}

example/src/main/java/eu/webeid/example/config/ValidationConfiguration.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,6 @@ public AuthTokenValidator validator(YAMLConfig yamlConfig) {
9191
}
9292
}
9393

94-
@Bean
95-
public YAMLConfig yamlConfig() {
96-
return new YAMLConfig();
97-
}
98-
9994
private X509Certificate[] loadTrustedCACertificatesFromCerFiles() {
10095
List<X509Certificate> caCertificates = new ArrayList<>();
10196

example/src/main/java/eu/webeid/example/config/YAMLConfig.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@
2323
package eu.webeid.example.config;
2424

2525
import java.time.Duration;
26+
import java.net.InetAddress;
27+
import java.net.URI;
28+
import java.net.URISyntaxException;
29+
import java.net.UnknownHostException;
30+
import org.apache.commons.lang3.StringUtils;
31+
import org.slf4j.Logger;
32+
import org.slf4j.LoggerFactory;
2633
import org.springframework.beans.factory.annotation.Value;
2734
import org.springframework.boot.context.properties.ConfigurationProperties;
2835
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -33,6 +40,8 @@
3340
@ConfigurationProperties(prefix = "web-eid-auth-token.validation")
3441
public class YAMLConfig {
3542

43+
private static final Logger LOG = LoggerFactory.getLogger(YAMLConfig.class);
44+
3645
@Value("local-origin")
3746
private String localOrigin;
3847

@@ -52,7 +61,27 @@ public String getLocalOrigin() {
5261
}
5362

5463
public void setLocalOrigin(String localOrigin) {
64+
if (StringUtils.endsWith(localOrigin, "/")) {
65+
throw new IllegalArgumentException("Configuration parameter local-origin cannot end with '/': " + localOrigin);
66+
}
5567
this.localOrigin = localOrigin;
68+
69+
// Intended for local development only:
70+
// When the Web-eID WebExtension developer setting ALLOW_HTTP_LOCALHOST is enabled,
71+
// then Web-eID permits the extension to run over plain HTTP on localhost,
72+
// but Web-eID app will still use protocol HTTPS in origin. Thus, we fake it here to make sure message validates.
73+
if (StringUtils.startsWith(localOrigin, "http:")) {
74+
try {
75+
if (InetAddress.getByName(new URI(localOrigin).getHost()).isLoopbackAddress()) {
76+
this.localOrigin = localOrigin.replaceFirst("^http:", "https:");
77+
LOG.warn("Configuration local-origin contains http protocol {}, which is not supported. Replacing it with secure {}", localOrigin, this.localOrigin);
78+
}
79+
} catch (URISyntaxException e) {
80+
LOG.error("Configuration parameter origin-local does not contain an URL: {}", localOrigin, e);
81+
} catch (UnknownHostException e) {
82+
LOG.error("Unable to determine if origin-local {} is loopback address", localOrigin, e);
83+
}
84+
}
5685
}
5786

5887
public String getSiteCertHash() {
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
spring.profiles.active=dev
2-
server.servlet.session.cookie.name=__Host-JSESSIONID
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package eu.webeid.example.config;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import jakarta.servlet.ServletContext;
6+
import jakarta.servlet.SessionCookieConfig;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.boot.test.context.SpringBootTest;
10+
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
11+
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
12+
import org.springframework.test.context.TestPropertySource;
13+
14+
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
15+
@TestPropertySource(properties = {"web-eid-auth-token.validation.local-origin=http://localhost"})
16+
class CookieHttpTest {
17+
18+
@Autowired
19+
private ServletWebServerApplicationContext context;
20+
21+
@Test
22+
void whenLocalOriginStartsWithHttp_thenCookeDoesNotHaveHostPrefix() {
23+
ServletContext servletContext = context.getServletContext();
24+
SessionCookieConfig cookieConfig = servletContext.getSessionCookieConfig();
25+
assertThat(cookieConfig.getName()).isEqualTo("JSESSIONID");
26+
}
27+
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package eu.webeid.example.config;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import jakarta.servlet.ServletContext;
6+
import jakarta.servlet.SessionCookieConfig;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.boot.test.context.SpringBootTest;
10+
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
11+
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
12+
import org.springframework.test.context.TestPropertySource;
13+
14+
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
15+
@TestPropertySource(properties = {"web-eid-auth-token.validation.local-origin=https://localhost"})
16+
class CookieHttpsTest {
17+
18+
@Autowired
19+
private ServletWebServerApplicationContext context;
20+
21+
@Test
22+
void whenLocalOriginStartsWithHttp_thenCookeDoesNotHaveHostPrefix() {
23+
ServletContext servletContext = context.getServletContext();
24+
SessionCookieConfig cookieConfig = servletContext.getSessionCookieConfig();
25+
assertThat(cookieConfig.getName()).isEqualTo("__Host-JSESSIONID");
26+
}
27+
28+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package eu.webeid.example.config;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
7+
import org.apache.commons.lang3.StringUtils;
8+
import org.junit.jupiter.api.Test;
9+
import org.junit.jupiter.params.ParameterizedTest;
10+
import org.junit.jupiter.params.provider.ValueSource;
11+
12+
class YAMLConfigTest {
13+
14+
@ValueSource(strings = {
15+
"http://localhost",
16+
"http://localhost:8080",
17+
"http://127.0.0.1",
18+
"http://127.0.0.1:8080",
19+
"http://[::1]",
20+
"http://[::1]:8080",
21+
"http://[0000:0000:0000:0000:0000:0000:0000:0001]",
22+
"http://[0000:0000:0000:0000:0000:0000:0000:0001]:8080"
23+
})
24+
@ParameterizedTest
25+
void givenLocalOriginHttpLoopbackAddress_whenParsingLocalOrigin_thenItIsReplacedWithHttps(String origin) {
26+
YAMLConfig yamlConfig = new YAMLConfig();
27+
yamlConfig.setLocalOrigin(origin);
28+
assertThat(yamlConfig.getLocalOrigin()).isEqualTo(origin.replaceFirst("^http:", "https:"));
29+
}
30+
31+
@ValueSource(strings = {
32+
"https://localhost",
33+
"https://localhost:8080",
34+
"https://127.0.0.1",
35+
"https://127.0.0.1:8080",
36+
"https://[::1]",
37+
"https://[::1]:8080",
38+
"https://[0000:0000:0000:0000:0000:0000:0000:0001]",
39+
"https://[0000:0000:0000:0000:0000:0000:0000:0001]:8080"
40+
})
41+
@ParameterizedTest
42+
void givenLocalOriginHttpsLoopbackAddress_whenParsingLocalOrigin_thenOriginalIsKept(String origin) {
43+
YAMLConfig yamlConfig = new YAMLConfig();
44+
yamlConfig.setLocalOrigin(origin);
45+
assertThat(yamlConfig.getLocalOrigin()).isEqualTo(origin);
46+
}
47+
48+
@ValueSource(strings = {
49+
"http://somename.app",
50+
"http://somename.app:8080",
51+
"http://8.8.8.8",
52+
"http://8.8.8.8:8080",
53+
"http://[2001:4860:4860::8888]",
54+
"http://[2001:4860:4860::8888]:8080",
55+
})
56+
@ParameterizedTest
57+
void givenLocalOriginHttpNonLoopbackAddress_whenParsingLocalOrigin_thenOriginalIsKept(String origin) {
58+
YAMLConfig yamlConfig = new YAMLConfig();
59+
yamlConfig.setLocalOrigin(origin);
60+
assertThat(yamlConfig.getLocalOrigin()).isEqualTo(origin);
61+
}
62+
63+
@ValueSource(strings = {
64+
"https://localhost/",
65+
"https://localhost:8080/"
66+
})
67+
@ParameterizedTest
68+
void givenLocalOriginThatEndsWithSlash_whenParsingLocalOrigin_thenExceptionIsThrown(String origin) {
69+
YAMLConfig yamlConfig = new YAMLConfig();
70+
assertThatThrownBy(() -> yamlConfig.setLocalOrigin(origin))
71+
.hasMessage("Configuration parameter local-origin cannot end with '/': " + origin);
72+
}
73+
}

0 commit comments

Comments
 (0)