Skip to content

Commit 2f52b3a

Browse files
committed
Add options to configure Web session cookie
1 parent 70e6235 commit 2f52b3a

File tree

11 files changed

+233
-50
lines changed

11 files changed

+233
-50
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
# Version 3.10.0 (2019-04-30)
22

33
* [new] Support JSR-250 `@PostConstruct` and `@PreDestroy` annotations on singletons (in addition to AutoCloseable `close()` method).
4-
* [new] New `SeedInterceptor` API to declare method interceptors without coupling to Guice implementation.
4+
* [new] Add `SeedInterceptor` API to declare method interceptors without coupling to Guice implementation.
5+
* [new] Add `web.sessions.cookie` configuration options to set Web session cookie details.
6+
* [chg] Moved `web.server.sessions` configuration options to `web.sessions`.
7+
* [chg] Default session timeout with embedded servers is now defined by the `web.server.` configuration options to `web.sessions`.
8+
* [chg] Renamed `web.staticResources` configuration options to `web.static`.
59
* [fix] Ensure that JVM-wide base configuration is refreshed between tests.
610
* [fix] With Jersey 2, allow JAX-RS components to be instantiated without Guice as a fallback.
11+
* [fix] Default session timeout for Undertow was incorrect. It is now 20 minutes.
712

813
# Version 3.9.1 (2019-12-17)
914

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@
215215
<exclude>org.seedstack.seed.spi.DependencyProvider</exclude>
216216
<exclude>org.seedstack.seed.web.spi.AntiXsrfService</exclude>
217217
<exclude>org.seedstack.seed.crypto.CryptoConfig</exclude>
218+
<exclude>org.seedstack.seed.web.WebConfig</exclude>
218219
</excludes>
219220
</parameter>
220221
</configuration>

web/core/src/main/java/org/seedstack/seed/web/internal/SeedServletContainerInitializer.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
* License, v. 2.0. If a copy of the MPL was not distributed with this
66
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
77
*/
8+
89
package org.seedstack.seed.web.internal;
910

10-
import static java.util.EnumSet.of;
11-
import static javax.servlet.SessionTrackingMode.valueOf;
1211
import static org.seedstack.seed.web.internal.ServletContextUtils.INJECTOR_ATTRIBUTE_NAME;
1312
import static org.seedstack.seed.web.internal.ServletContextUtils.KERNEL_ATTRIBUTE_NAME;
1413

@@ -17,12 +16,13 @@
1716
import io.nuun.kernel.api.config.KernelConfiguration;
1817
import io.nuun.kernel.core.NuunCore;
1918
import java.util.Enumeration;
19+
import java.util.Optional;
2020
import java.util.Set;
2121
import javax.servlet.ServletContainerInitializer;
2222
import javax.servlet.ServletContext;
2323
import javax.servlet.ServletContextEvent;
2424
import javax.servlet.ServletContextListener;
25-
import javax.servlet.ServletException;
25+
import javax.servlet.SessionCookieConfig;
2626
import org.seedstack.seed.core.Seed;
2727
import org.seedstack.seed.web.WebConfig;
2828
import org.seedstack.shed.exception.BaseException;
@@ -31,9 +31,10 @@ public class SeedServletContainerInitializer implements ServletContainerInitiali
3131
private Kernel kernel;
3232

3333
@Override
34-
public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
34+
public void onStartup(Set<Class<?>> classes, ServletContext servletContext) {
3535
WebConfig webConfig = Seed.baseConfiguration().get(WebConfig.class);
36-
servletContext.setSessionTrackingModes(of(valueOf(webConfig.getSessionTrackingMode().name())));
36+
servletContext.setSessionTrackingModes(webConfig.sessions().getTrackingModes());
37+
copyConfig(webConfig.sessions().cookie(), servletContext.getSessionCookieConfig());
3738

3839
try {
3940
kernel = Seed.createKernel(servletContext, buildKernelConfiguration(servletContext), true);
@@ -90,4 +91,14 @@ private void handleException(Exception e) throws BaseException {
9091
}
9192
throw translated;
9293
}
94+
95+
private void copyConfig(WebConfig.SessionsConfig.CookieConfig src, SessionCookieConfig dest) {
96+
Optional.ofNullable(src.getComment()).ifPresent(dest::setComment);
97+
Optional.ofNullable(src.getDomain()).ifPresent(dest::setDomain);
98+
Optional.ofNullable(src.getName()).ifPresent(dest::setName);
99+
Optional.ofNullable(src.getPath()).ifPresent(dest::setPath);
100+
dest.setHttpOnly(src.isHttpOnly());
101+
dest.setSecure(src.isSecure());
102+
dest.setMaxAge(src.getMaxAge());
103+
}
93104
}

web/core/src/test/java/org/seedstack/seed/web/ServletIT.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
* License, v. 2.0. If a copy of the MPL was not distributed with this
66
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
77
*/
8+
89
package org.seedstack.seed.web;
910

1011
import io.restassured.RestAssured;
12+
import io.restassured.matcher.RestAssuredMatchers;
1113
import java.net.URL;
1214
import org.assertj.core.api.Assertions;
1315
import org.hamcrest.Matchers;
@@ -17,7 +19,6 @@
1719
import org.jboss.arquillian.test.api.ArquillianResource;
1820
import org.jboss.shrinkwrap.api.ShrinkWrap;
1921
import org.jboss.shrinkwrap.api.spec.WebArchive;
20-
import org.junit.BeforeClass;
2122
import org.junit.Test;
2223
import org.junit.runner.RunWith;
2324
import org.seedstack.seed.web.fixtures.servlet.TestFilter;
@@ -99,4 +100,18 @@ public void filterParamsAreCorrectlyInitialized() {
99100
.when()
100101
.get(baseUrl + "testFilter1");
101102
}
103+
104+
@Test
105+
@RunAsClient
106+
public void sessionCookieConfigIsHonored() {
107+
RestAssured.expect()
108+
.statusCode(200)
109+
.cookie("CUSTOM_SESSION_ID", RestAssuredMatchers.detailedCookie()
110+
.maxAge(15)
111+
.comment("Custom")
112+
.httpOnly(true)
113+
)
114+
.when()
115+
.get(baseUrl + "sessionTest");
116+
}
102117
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright © 2013-2020, The SeedStack authors <http://seedstack.org>
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
7+
*/
8+
package org.seedstack.seed.web.fixtures.servlet;
9+
10+
import javax.servlet.annotation.WebServlet;
11+
import javax.servlet.http.HttpServlet;
12+
import javax.servlet.http.HttpServletRequest;
13+
import javax.servlet.http.HttpServletResponse;
14+
15+
@WebServlet(value = "/sessionTest")
16+
public class SessionTestServlet extends HttpServlet {
17+
@Override
18+
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
19+
req.getSession(true).setAttribute("test", "test");
20+
}
21+
}

web/core/src/test/resources/application.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
#
88

99
web:
10+
sessions:
11+
cookie:
12+
comment: Custom
13+
name: CUSTOM_SESSION_ID
14+
httpOnly: true
15+
maxAge: 15
1016
cors:
1117
enabled: true
1218
properties:

web/specs/src/main/java/org/seedstack/seed/web/WebConfig.java

Lines changed: 122 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@
55
* License, v. 2.0. If a copy of the MPL was not distributed with this
66
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
77
*/
8+
89
package org.seedstack.seed.web;
910

1011
import java.util.ArrayList;
1112
import java.util.Collections;
1213
import java.util.HashMap;
14+
import java.util.HashSet;
1315
import java.util.List;
1416
import java.util.Map;
17+
import java.util.Set;
18+
import javax.servlet.SessionTrackingMode;
1519
import javax.validation.constraints.Max;
1620
import javax.validation.constraints.Min;
1721
import org.seedstack.coffig.Config;
@@ -20,11 +24,28 @@
2024

2125
@Config("web")
2226
public class WebConfig {
23-
private boolean requestDiagnostic;
24-
private SessionTrackingMode sessionTrackingMode = SessionTrackingMode.COOKIE;
27+
private SessionsConfig sessions = new SessionsConfig();
28+
@Config("static")
2529
private StaticResourcesConfig staticResources = new StaticResourcesConfig();
2630
private CORSConfig cors = new CORSConfig();
27-
private ServerConfig serverConfig = new ServerConfig();
31+
private ServerConfig server = new ServerConfig();
32+
private boolean requestDiagnostic;
33+
34+
public SessionsConfig sessions() {
35+
return sessions;
36+
}
37+
38+
public StaticResourcesConfig staticResources() {
39+
return staticResources;
40+
}
41+
42+
public CORSConfig cors() {
43+
return cors;
44+
}
45+
46+
public ServerConfig server() {
47+
return server;
48+
}
2849

2950
public boolean isRequestDiagnosticEnabled() {
3051
return requestDiagnostic;
@@ -35,31 +56,102 @@ public WebConfig setRequestDiagnostic(boolean requestDiagnostic) {
3556
return this;
3657
}
3758

38-
public SessionTrackingMode getSessionTrackingMode() {
39-
return sessionTrackingMode;
40-
}
59+
@Config("sessions")
60+
public static class SessionsConfig {
61+
private Set<SessionTrackingMode> trackingModes;
62+
private CookieConfig cookie = new CookieConfig();
4163

42-
public WebConfig setSessionTrackingMode(SessionTrackingMode sessionTrackingMode) {
43-
this.sessionTrackingMode = sessionTrackingMode;
44-
return this;
45-
}
64+
public SessionsConfig() {
65+
trackingModes = new HashSet<>();
66+
trackingModes.add(SessionTrackingMode.COOKIE);
67+
}
4668

47-
public StaticResourcesConfig staticResources() {
48-
return staticResources;
49-
}
69+
public Set<javax.servlet.SessionTrackingMode> getTrackingModes() {
70+
return trackingModes;
71+
}
5072

51-
public CORSConfig cors() {
52-
return cors;
53-
}
73+
public SessionsConfig setTrackingModes(Set<javax.servlet.SessionTrackingMode> trackingModes) {
74+
this.trackingModes = trackingModes;
75+
return this;
76+
}
5477

55-
public ServerConfig serverConfig() {
56-
return serverConfig;
57-
}
78+
public CookieConfig cookie() {
79+
return cookie;
80+
}
81+
82+
@Config("cookie")
83+
public static class CookieConfig {
84+
private boolean httpOnly = false;
85+
private boolean secure = false;
86+
private int maxAge = -1;
87+
private String comment;
88+
private String domain;
89+
private String name;
90+
private String path;
91+
92+
public boolean isHttpOnly() {
93+
return httpOnly;
94+
}
95+
96+
public CookieConfig setHttpOnly(boolean httpOnly) {
97+
this.httpOnly = httpOnly;
98+
return this;
99+
}
100+
101+
public boolean isSecure() {
102+
return secure;
103+
}
104+
105+
public CookieConfig setSecure(boolean secure) {
106+
this.secure = secure;
107+
return this;
108+
}
109+
110+
public int getMaxAge() {
111+
return maxAge;
112+
}
113+
114+
public CookieConfig setMaxAge(int maxAge) {
115+
this.maxAge = maxAge;
116+
return this;
117+
}
118+
119+
public String getComment() {
120+
return comment;
121+
}
122+
123+
public CookieConfig setComment(String comment) {
124+
this.comment = comment;
125+
return this;
126+
}
127+
128+
public String getDomain() {
129+
return domain;
130+
}
131+
132+
public CookieConfig setDomain(String domain) {
133+
this.domain = domain;
134+
return this;
135+
}
58136

59-
public enum SessionTrackingMode {
60-
COOKIE,
61-
SSL,
62-
URL
137+
public String getName() {
138+
return name;
139+
}
140+
141+
public CookieConfig setName(String name) {
142+
this.name = name;
143+
return this;
144+
}
145+
146+
public String getPath() {
147+
return path;
148+
}
149+
150+
public CookieConfig setPath(String path) {
151+
this.path = path;
152+
return this;
153+
}
154+
}
63155
}
64156

65157
@Config("cors")
@@ -168,7 +260,6 @@ public static class ServerConfig {
168260
private static final String DEFAULT_WELCOME_FILE = "index.html";
169261
private static final boolean DEFAULT_PREFER_HTTPS = true;
170262

171-
private SessionsConfig sessions = new SessionsConfig();
172263
private WebSocketConfig websocket = new WebSocketConfig();
173264
private String host = DEFAULT_HOST;
174265
@SingleValue
@@ -187,15 +278,12 @@ public static class ServerConfig {
187278
private boolean preferHttps = DEFAULT_PREFER_HTTPS;
188279
private List<String> welcomeFiles = new ArrayList<>();
189280
private List<ErrorPage> errorPages = new ArrayList<>();
281+
private int defaultSessionTimeout = 60 * 20;
190282

191283
public ServerConfig() {
192284
addWelcomeFile(DEFAULT_WELCOME_FILE);
193285
}
194286

195-
public SessionsConfig sessions() {
196-
return sessions;
197-
}
198-
199287
public WebSocketConfig webSocket() {
200288
return websocket;
201289
}
@@ -307,20 +395,13 @@ public ServerConfig addErrorPage(ErrorPage errorPage) {
307395
return this;
308396
}
309397

310-
@Config("sessions")
311-
public static class SessionsConfig {
312-
private static final int DEFAULT_SESSION_TIMEOUT = 1000 * 60 * 15;
313-
@SingleValue
314-
private int timeout = DEFAULT_SESSION_TIMEOUT;
315-
316-
public int getTimeout() {
317-
return timeout;
318-
}
398+
public int getDefaultSessionTimeout() {
399+
return defaultSessionTimeout;
400+
}
319401

320-
public SessionsConfig setTimeout(int timeout) {
321-
this.timeout = timeout;
322-
return this;
323-
}
402+
public ServerConfig setDefaultSessionTimeout(int defaultSessionTimeout) {
403+
this.defaultSessionTimeout = defaultSessionTimeout;
404+
return this;
324405
}
325406

326407
@Config("websocket")

web/undertow/src/main/java/org/seedstack/seed/undertow/internal/DeploymentManagerFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* License, v. 2.0. If a copy of the MPL was not distributed with this
66
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
77
*/
8+
89
package org.seedstack.seed.undertow.internal;
910

1011
import static org.seedstack.shed.ClassLoaders.findMostCompleteClassLoader;
@@ -70,7 +71,7 @@ private DeploymentInfo configureDeploymentInfo() {
7071
.setClassLoader(mostCompleteClassLoader)
7172
.setDeploymentName(applicationConfig.getId())
7273
.setDisplayName(applicationConfig.getName())
73-
.setDefaultSessionTimeout(serverConfig.sessions().getTimeout())
74+
.setDefaultSessionTimeout(serverConfig.getDefaultSessionTimeout())
7475
.setResourceManager(new ClassPathResourceManager(mostCompleteClassLoader, META_INF_RESOURCES))
7576
.addWelcomePages(serverConfig.getWelcomeFiles())
7677
.addErrorPages(buildUndertowErrorPages(serverConfig.getErrorPages()))

0 commit comments

Comments
 (0)