Compare commits

..

148 Commits

Author SHA1 Message Date
Vedran Pavic
f7b7737896 Release 2.2.0.M1 2019-04-12 20:38:14 +02:00
Vedran Pavic
2a5b221d70 Update integration tests 2019-04-12 20:14:12 +02:00
Vedran Pavic
5a462b3594 Resolve indexes for Hazelcast session on write
Resolves: #1145
2019-04-12 20:08:54 +02:00
Vedran Pavic
c252c00a85 Upgrade Spring Data to Moore-M3
Resolves: #1317
2019-04-11 15:49:31 +02:00
Vedran Pavic
2a7b6ec4f7 Upgrade Spring Security to 5.2.0.M1
Resolves: #1318
2019-04-11 07:39:26 +02:00
Vedran Pavic
044e5bbe3c Upgrade Spring Framework to 5.2.0.M1
Resolves: #1348
2019-04-10 16:05:35 +02:00
Vedran Pavic
f247a78c32 Revert Derby dependency upgrade 2019-04-10 09:23:02 +02:00
Vedran Pavic
c0f708d0b3 Upgrade Reactor to Californium-SR6 2019-04-09 21:31:58 +02:00
Vedran Pavic
c2a3ffdb00 Upgrade Hazelcast to 3.12
Resolves: #1403
2019-04-09 21:28:45 +02:00
Vedran Pavic
856a9b2c51 Update integration tests 2019-04-09 21:24:55 +02:00
Vedran Pavic
0d24033749 Upgrade test dependencies 2019-04-09 21:19:01 +02:00
Vedran Pavic
7a5f9bc29e Polish 2019-03-29 21:41:09 +01:00
Vedran Pavic
094ffe8a60 Avoid conflicts with user provided RedisMessageListenerContainer
Resolves: #1252
2019-03-29 21:27:56 +01:00
Vedran Pavic
55102aa8bb Update to latest Checkstyle DTDs 2019-03-29 21:27:56 +01:00
Vedran Pavic
f2e9634789 Fix Checkstyle config 2019-03-29 21:27:56 +01:00
Vedran Pavic
7dccade893 Upgrade spring-build-conventions to 0.0.25.RELEASE 2019-03-29 21:27:54 +01:00
Vedran Pavic
39408ff42a Upgrade Gradle to 5.3.1 2019-03-29 17:54:09 +01:00
Spring Operator
a5a3bc5d0b URL Cleanup
This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener).

These URLs were fixed, but the https status was not OK. However, the https status was the same as the http request or http redirected to an https URL, so they were migrated. Your review is recommended.

* [ ] http://www.ultraq.net.nz/thymeleaf/layout (302) with 12 occurrences migrated to:
  https://github.com/ultraq/thymeleaf-layout-dialect ([https](https://www.ultraq.net.nz/thymeleaf/layout) result ConnectTimeoutException).
* [ ] http://192.168.1.100:8080/ (AnnotatedConnectException) with 1 occurrences migrated to:
  https://192.168.1.100:8080/ ([https](https://192.168.1.100:8080/) result ConnectTimeoutException).

These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended.

* [ ] http://docs.hazelcast.org/docs/ with 8 occurrences migrated to:
  https://docs.hazelcast.org/docs/ ([https](https://docs.hazelcast.org/docs/) result 200).
* [ ] http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/ with 1 occurrences migrated to:
  https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/ ([https](https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/) result 200).
* [ ] http://docs.spring.io/spring-session/docs/current/reference/html5/ with 1 occurrences migrated to:
  https://docs.spring.io/spring-session/docs/current/reference/html5/ ([https](https://docs.spring.io/spring-session/docs/current/reference/html5/) result 200).
* [ ] http://infinispan.org/docs/dev/user_guide/user_guide.html with 1 occurrences migrated to:
  https://infinispan.org/docs/dev/user_guide/user_guide.html ([https](https://infinispan.org/docs/dev/user_guide/user_guide.html) result 200).
* [ ] http://logback.qos.ch/manual/groovy.html with 1 occurrences migrated to:
  https://logback.qos.ch/manual/groovy.html ([https](https://logback.qos.ch/manual/groovy.html) result 200).
* [ ] http://projects.spring.io/spring-session/ with 1 occurrences migrated to:
  https://projects.spring.io/spring-session/ ([https](https://projects.spring.io/spring-session/) result 200).
* [ ] http://redis.io/commands/expire with 1 occurrences migrated to:
  https://redis.io/commands/expire ([https](https://redis.io/commands/expire) result 200).
* [ ] http://redis.io/commands/hmset with 1 occurrences migrated to:
  https://redis.io/commands/hmset ([https](https://redis.io/commands/hmset) result 200).
* [ ] http://redis.io/topics/data-types with 1 occurrences migrated to:
  https://redis.io/topics/data-types ([https](https://redis.io/topics/data-types) result 200).
* [ ] http://redis.io/topics/notifications with 2 occurrences migrated to:
  https://redis.io/topics/notifications ([https](https://redis.io/topics/notifications) result 200).
* [ ] http://stackoverflow.com with 1 occurrences migrated to:
  https://stackoverflow.com ([https](https://stackoverflow.com) result 200).
* [ ] http://stackoverflow.com/tags/spring-session with 1 occurrences migrated to:
  https://stackoverflow.com/tags/spring-session ([https](https://stackoverflow.com/tags/spring-session) result 200).
* [ ] http://www.thymeleaf.org with 12 occurrences migrated to:
  https://www.thymeleaf.org ([https](https://www.thymeleaf.org) result 200).
* [ ] http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd with 5 occurrences migrated to:
  https://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd ([https](https://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd) result 200).
* [ ] http://contributor-covenant.org with 1 occurrences migrated to:
  https://contributor-covenant.org ([https](https://contributor-covenant.org) result 301).
* [ ] http://contributor-covenant.org/version/1/3/0/ with 1 occurrences migrated to:
  https://contributor-covenant.org/version/1/3/0/ ([https](https://contributor-covenant.org/version/1/3/0/) result 301).
* [ ] http://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html with 2 occurrences migrated to:
  https://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html ([https](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html) result 301).
* [ ] http://www.maxmind.com with 2 occurrences migrated to:
  https://www.maxmind.com ([https](https://www.maxmind.com) result 302).

These URLs were intentionally ignored.

* http://java.sun.com/jsp/jstl/core with 8 occurrences
* http://localhost with 15 occurrences
* http://localhost:8080/ with 31 occurrences
* http://localhost:8080/h2-console/ with 3 occurrences
* http://localhost:8080/logout with 1 occurrences
* http://localhost:8080/test/index with 2 occurrences
* http://localhost:xxxxx/hazelcast/rest/maps/spring:session:sessions/7e8383a4-082c-4ffe-a4bc-c40fd3363c5e with 1 occurrences
* http://www.w3.org/1999/xhtml with 5 occurrences
* http://www.webjars.org/tags with 8 occurrences

Fixes gh-1375
2019-03-22 10:24:07 -04:00
Spring Operator
90c08340fa URL Cleanup
This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener).

These URLs were fixed, but the https status was not OK. However, the https status was the same as the http request or http redirected to an https URL, so they were migrated. Your review is recommended.

* http://www.puppycrawl.com/dtds/configuration_1_3.dtd (404) with 1 occurrences migrated to:
  https://www.puppycrawl.com/dtds/configuration_1_3.dtd ([https](https://www.puppycrawl.com/dtds/configuration_1_3.dtd) result 404).
* http://www.puppycrawl.com/dtds/suppressions_1_1.dtd (404) with 1 occurrences migrated to:
  https://www.puppycrawl.com/dtds/suppressions_1_1.dtd ([https](https://www.puppycrawl.com/dtds/suppressions_1_1.dtd) result 404).

These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended.

* http://www.hazelcast.com/schema/config/hazelcast-config-3.11.xsd with 3 occurrences migrated to:
  https://www.hazelcast.com/schema/config/hazelcast-config-3.11.xsd ([https](https://www.hazelcast.com/schema/config/hazelcast-config-3.11.xsd) result 200).
* http://www.springframework.org/schema/beans/spring-beans.xsd with 9 occurrences migrated to:
  https://www.springframework.org/schema/beans/spring-beans.xsd ([https](https://www.springframework.org/schema/beans/spring-beans.xsd) result 200).
* http://www.springframework.org/schema/context/spring-context.xsd with 7 occurrences migrated to:
  https://www.springframework.org/schema/context/spring-context.xsd ([https](https://www.springframework.org/schema/context/spring-context.xsd) result 200).
* http://www.springframework.org/schema/jdbc/spring-jdbc.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/jdbc/spring-jdbc.xsd ([https](https://www.springframework.org/schema/jdbc/spring-jdbc.xsd) result 200).
* http://www.springframework.org/schema/security/spring-security.xsd with 2 occurrences migrated to:
  https://www.springframework.org/schema/security/spring-security.xsd ([https](https://www.springframework.org/schema/security/spring-security.xsd) result 200).
* http://www.springframework.org/schema/util/spring-util-4.1.xsd with 2 occurrences migrated to:
  https://www.springframework.org/schema/util/spring-util-4.1.xsd ([https](https://www.springframework.org/schema/util/spring-util-4.1.xsd) result 200).
* http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd with 2 occurrences migrated to:
  https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd ([https](https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd) result 302).

These URLs were intentionally ignored.

* http://java.sun.com/xml/ns/javaee with 4 occurrences
* http://www.hazelcast.com/schema/config with 6 occurrences
* http://www.springframework.org/schema/beans with 18 occurrences
* http://www.springframework.org/schema/context with 14 occurrences
* http://www.springframework.org/schema/jdbc with 2 occurrences
* http://www.springframework.org/schema/p with 5 occurrences
* http://www.springframework.org/schema/security with 4 occurrences
* http://www.springframework.org/schema/util with 4 occurrences
* http://www.w3.org/2001/XMLSchema-instance with 14 occurrences

Fixes gh-1374
2019-03-21 16:59:05 -04:00
Rob Winch
13208dd3b5 Update Checkstyle to https Apache 2 License
Issue gh-1369
2019-03-14 22:27:27 -05:00
Spring Operator
0975d4d47e URL Cleanup
This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener).

# Fixed URLs

## Fixed Success
These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended.

* http://www.apache.org/licenses/ with 1 occurrences migrated to:
  https://www.apache.org/licenses/ ([https](https://www.apache.org/licenses/) result 200).
* http://www.apache.org/licenses/LICENSE-2.0 with 269 occurrences migrated to:
  https://www.apache.org/licenses/LICENSE-2.0 ([https](https://www.apache.org/licenses/LICENSE-2.0) result 200).
* http://www.apache.org/licenses/LICENSE-2.0.html with 1 occurrences migrated to:
  https://www.apache.org/licenses/LICENSE-2.0.html ([https](https://www.apache.org/licenses/LICENSE-2.0.html) result 200).
2019-03-14 20:39:41 -05:00
Vedran Pavic
0c0bfa4414 Remove special handling for Servlet 3.0 and below
Closes: #1363
2019-03-14 21:59:45 +01:00
Vedran Pavic
8b40e8cce8 Rework RedisHttpSessionConfiguration to bean method invocations
Closes: #1362
2019-03-14 21:34:53 +01:00
Vedran Pavic
408f2da108 Start building against Spring Data Moore snapshots
See: #1317
2019-03-13 18:18:16 +01:00
Vedran Pavic
3b7bb7ec12 Start building against Spring Framework 5.2 snapshots
See: #1348
2019-03-13 18:18:16 +01:00
Vedran Pavic
4c849caccd Next development version 2019-03-13 18:09:34 +01:00
Vedran Pavic
ea84b8bd22 Upgrade samples to Spring Boot 2.1.3.RELEASE
Resolves: #1357
2019-03-12 18:29:26 +01:00
Jay Bryant
0c9fbedd05 Editing pass
I edited for spelling, grammar, punctuation, usage, and corporate voice, with the goal of making this content be consistent with our other content.
2019-02-15 13:33:51 -06:00
Rob Winch
08495b1321 Next Development Version 2019-02-13 19:55:46 -06:00
Rob Winch
60cd6d8be6 Release 2.1.4.RELEASE 2019-02-13 15:55:29 -06:00
Rob Winch
5503057523 Update to Spring Security 5.1.4
Fixes: gh-1329
2019-02-13 15:54:46 -06:00
Vedran Pavic
8fc2f1130a Update integration tests 2019-02-13 19:36:48 +01:00
Vedran Pavic
f5d63efcf1 Upgrade test dependencies 2019-02-13 19:32:40 +01:00
Vedran Pavic
ed76514f30 Upgrade spring-build-conventions to 0.0.23.RELEASE 2019-02-13 19:26:19 +01:00
Vedran Pavic
e1c0d62d33 Upgrade Reactor to Californium-SR5
Resolves: #1326
2019-02-13 19:24:42 +01:00
Vedran Pavic
8041358d18 Upgrade Spring Data to Lovelace-SR5
Resolves: #1325
2019-02-13 19:24:09 +01:00
Vedran Pavic
cdd85cb349 Upgrade Spring Framework to 5.1.5.RELEASE
Resolves: #1324
2019-02-13 19:23:46 +01:00
Vedran Pavic
381a07cb8c Ignore failed rename operation for deleted session
In scenario with concurrent requests attempting to change session id, the "ERR no such key" error will occur for a thread that comes in second. This commit addresses the problem by ignoring the aforementioned error.

Resolves: #1270
2019-01-29 21:29:10 +01:00
Vedran Pavic
0e89539e20 Upgrade samples to Spring Boot 2.1.2.RELEASE
Resolves: #1318
2019-01-16 22:15:51 +01:00
Vedran Pavic
f00a1b9c6f Fix HazelcastSessionRepository to update TTL when maxInactiveInterval is changed
Resolves: #1300
2019-01-12 12:22:45 +01:00
Rob Winch
39cecb0902 Next Development Version 2019-01-10 21:36:58 -06:00
Rob Winch
c5fc4b57ad Release 2.1.3.RELEASE 2019-01-10 21:36:09 -06:00
Rob Winch
3b826e51a1 Update to Spring Security 5.1.3.RELEASE
Fixes: gh-1293
2019-01-10 21:34:44 -06:00
Vedran Pavic
67063ec0c6 Upgrade Gradle to 4.10.3 2019-01-10 16:22:39 +01:00
Vedran Pavic
72198e9e80 Update integration tests 2019-01-10 16:19:38 +01:00
Vedran Pavic
b3ee28b972 Upgrade test dependencies 2019-01-10 16:13:41 +01:00
Vedran Pavic
2d498bf69d Upgrade Spring Data to Lovelace-SR4
Resolves: #1292
2019-01-10 14:20:50 +01:00
Vedran Pavic
c365e4d941 Upgrade Spring Framework to 5.1.4.RELEASE
Resolves: #1291
2019-01-09 16:21:37 +01:00
Vedran Pavic
f7f8d4f6c0 Upgrade Reactor to Californium-SR4
Resolves: #1298
2019-01-08 17:59:54 +01:00
Vedran Pavic
fd5115fae5 Fix Spring Security integration docs sample 2019-01-08 08:15:08 +01:00
Vedran Pavic
a4c39fde9f Polish 2018-12-26 20:16:32 +01:00
Vedran Pavic
96391ce41a Fix assertion in Hazelcast tests 2018-12-24 20:59:06 +01:00
Vedran Pavic
d48eebea99 Upgrade Hazelcast to 3.11.1
Resolves: #1299
2018-12-20 18:52:27 +01:00
Vedran Pavic
57cd6c367d Upgrade samples to Spring Boot 2.1.1.RELEASE
Resolves: #1294
2018-12-17 21:12:38 +01:00
Roman Beskrovnyi
68f83b00eb Fix SessionRepositoryFilter Javadoc 2018-12-12 13:57:48 -06:00
Jeff
a4a5b529ef Fix RedisOperationsSessionRepository javadoc typos
Resolves: #1273
2018-12-04 16:35:56 +01:00
Vedran Pavic
f5ae38d94c Next development version 2018-11-28 19:43:47 +01:00
Vedran Pavic
b201ed971c Release 2.1.2.RELEASE 2018-11-28 19:38:37 +01:00
Vedran Pavic
70346b0a84 Upgrade test dependencies 2018-11-28 19:14:15 +01:00
Vedran Pavic
d4fd8b97b4 Upgrade Spring Security to 5.1.2.RELEASE
Resolves: #1261
2018-11-28 15:57:45 +01:00
Vedran Pavic
b3d01063d9 Upgrade Spring Data to Lovelace-SR3
Resolves: #1249
2018-11-27 15:20:19 +01:00
Vedran Pavic
124565306b Tweak Hazelcast session event tests
See: #1267
2018-11-27 13:21:16 +01:00
Vedran Pavic
f709a6c787 Upgrade Hazelcast to 3.11
Resolves: #1267
2018-11-27 11:29:48 +01:00
Vedran Pavic
c354927ef3 Upgrade spring-build-conventions to 0.0.22.RELEASE 2018-11-27 11:29:37 +01:00
Vedran Pavic
2db79e2bb8 Upgrade Spring Framework to 5.1.3.RELEASE
Resolves: #1248
2018-11-27 11:29:10 +01:00
Vedran Pavic
3480c65c2b Polish 2018-11-26 18:24:14 +01:00
Vedran Pavic
e0dc0262ef Make SessionUpdateEntryProcessor public
Resolves: #1260
2018-11-26 18:18:18 +01:00
Vedran Pavic
3b7da0c370 Update integration tests 2018-11-26 17:54:57 +01:00
Vedran Pavic
72984f9ca6 Upgrade test dependencies 2018-11-26 17:42:00 +01:00
Vedran Pavic
8a4872b919 Improve exception asserts 2018-11-26 10:02:40 +01:00
Vedran Pavic
6b6c6f27df Upgrade Reactor to Californium-SR3
Resolves: #1262
2018-11-23 19:26:15 +01:00
Vedran Pavic
640bee3fc4 Update Jenkins pipeline
- add JDK 9 stage (only unit tests)
- update JDK 10 stage to only run unit tests
2018-11-22 23:11:31 +01:00
Vedran Pavic
3bfdb9be93 Polish contribution
Resolves: #1243
2018-11-02 22:28:34 +01:00
Josh Cummings
c8f3d1a1ec Commit Session on Include Dispatch
The servlet spec disallows any writing of headers after an include has been issued.

This commit intercepts the include and commits the session, then
allowing the include to proceed.

See: #1243
2018-11-02 22:28:34 +01:00
Vedran Pavic
11ad1db6e7 Update integration tests 2018-11-01 17:50:35 +01:00
Vedran Pavic
7b87128db6 Upgrade test dependencies 2018-11-01 17:28:06 +01:00
Vedran Pavic
bf861933ed Upgrade samples to Spring Boot 2.1.0.RELEASE
Resolves: #1240
2018-11-01 17:24:59 +01:00
Rob Winch
979e91256d Next Development Version 2018-10-29 10:42:02 -05:00
Rob Winch
05986d68b2 Release 2.1.1.RELEASE 2018-10-29 10:08:49 -05:00
Rob Winch
e17b047800 Update to Spring Data Lovelace-SR2
Fixes: gh-1234
2018-10-29 10:07:26 -05:00
Vedran Pavic
5ab2424b14 Upgrade Spring Framework to 5.1.2.RELEASE
Resolves: #1233
2018-10-29 13:04:47 +01:00
Vedran Pavic
196919efbb Upgrade Reactor to Californium-SR2
Resolves: #1235
2018-10-29 07:37:17 +01:00
Vedran Pavic
717e16cb71 Ensure HttpServletRequest#getRequestedSessionId API is respected
HttpSessionIdResolver supports resolving multiple requested session ids associated with the request - as a consequence, we need to validate the existence of requested session before returning the id. However, if no presented session ids do validate the null is returned, which violates the HttpServletRequest#getRequestedSessionId API.

This commit ensures that if no presented session ids are valid, we respect the HttpServletRequest#getRequestedSessionId API by returning first requested session id.

Resolves: #1229
2018-10-26 19:55:37 +02:00
Rob Winch
5f1b7d6722 Next Development Version 2018-10-15 20:05:12 -05:00
Rob Winch
4d3a01919c Release 2.1.0.RELEASE 2018-10-15 20:04:27 -05:00
Rob Winch
e408d7f557 Update to Spring Security 5.1.1.RELEASE
Fixes: gh-1222
2018-10-15 20:04:04 -05:00
Vedran Pavic
f34acebf84 Upgrade integration tests 2018-10-15 18:42:12 +02:00
Vedran Pavic
1aab3e8285 Upgrade test dependencies 2018-10-15 18:35:18 +02:00
Vedran Pavic
c3528996d2 Upgrade Hazelcast to 3.10.6
Resolves: #1223
2018-10-15 18:34:44 +02:00
Vedran Pavic
3ccc3eb6e1 Upgrade Reactor to Californium-SR1
Resolves: #1221
2018-10-15 18:34:10 +02:00
Vedran Pavic
de76be95ac Upgrade Spring Data to Lovelace-SR1
Resolves: #1220
2018-10-15 18:33:25 +02:00
Vedran Pavic
bc127ab3fc Upgrade Spring Framework to 5.1.1.RELEASE
Resolves: #1219
2018-10-15 18:32:47 +02:00
Vedran Pavic
3e9f6a35c4 Fix root project name 2018-10-01 22:46:10 +02:00
Vedran Pavic
49daa3a9c7 Polish 2018-09-26 14:16:02 +02:00
Vedran Pavic
a67bd634d9 Disable network join in Hazelcast samples 2018-09-26 14:16:00 +02:00
Vedran Pavic
2762f001bf Add Oracle integration tests 2018-09-25 19:10:15 +02:00
Vedran Pavic
93aee206fb Configure default LobHandler to use temporary LOBs on Oracle
JdbcOperationsSessionRepository recently introduced validation when inserting new session attributes in order to prevent data integrity violations in highly concurrent environments. This is done by using INSERT INTO ... SELECT statement to verify existence of session record in parent table. Such arrangement causes problems with Oracle if inserted attribute is of size 4 kb or more.

This commit enhances JdbcHttpSessionConfiguration to detect Oracle database is used, and set createTemporaryLob option on default LobHandler to true.

Resolves: #1203
See also: #1031
2018-09-25 18:45:02 +02:00
Vedran Pavic
3df3b30117 Upgrade Testcontainers to 1.9.1 2018-09-25 18:31:52 +02:00
Vedran Pavic
5fb0c4dd35 Improve JDBC integration tests 2018-09-24 06:30:47 +02:00
Vedran Pavic
6fbce6e3e8 Next development version 2018-09-21 21:27:42 +02:00
Vedran Pavic
a3fd05326a Release 2.1.0.RC1 2018-09-21 21:26:28 +02:00
Vedran Pavic
4c6dc976b3 Upgrade Testcontainers to 1.9.0-rc2 2018-09-21 19:22:12 +02:00
Vedran Pavic
58ae28b0a0 Fix SpringSessionRememberMeServices documentation example
Resolves: #1157
2018-09-21 19:05:33 +02:00
Vedran Pavic
3e98ecf234 Upgrade Spring Security to 5.1.0.RELEASE
Resolves: #1188
2018-09-21 19:01:15 +02:00
Vedran Pavic
41ed429f98 Upgrade Spring Data to Lovelace-RELEASE
Resolves: #1190
2018-09-21 19:00:38 +02:00
Vedran Pavic
def15b05ca Upgrade Spring Framework to 5.1.0.RELEASE
Resolves: #1187
2018-09-21 11:10:33 +02:00
Vedran Pavic
eae8592f2b Upgrade integration tests 2018-09-20 19:48:33 +02:00
Vedran Pavic
81460ede09 Make SessionUpdateEntryProcessor implement Offloadable
Resolves: #1204
2018-09-20 19:31:55 +02:00
Vedran Pavic
ca4ec9a557 Upgrade test dependencies 2018-09-20 19:23:24 +02:00
Vedran Pavic
fd2165f471 Upgrade Hazelcast to 3.10.5
Resolves: #1206
2018-09-20 19:23:24 +02:00
Vedran Pavic
ad1e57a1fe Upgrade Gradle to 4.10.2 2018-09-20 19:15:26 +02:00
Vedran Pavic
0ffcaa2d35 Upgrade Reactor to Californium-RELEASE
Resolves: #1189
2018-09-20 11:45:33 +02:00
Vedran Pavic
b61937def7 Polish contribution
Resolves: #1133
2018-09-19 23:53:38 +02:00
Craig Andrews
c523fb591d Deserialize attributes lazily in JdbcOperationsSessionRepository
Instead of deserializing all of the session attributes as they are read from the database, deserialize as #getAttribute requests them.

See: #1133
2018-09-19 23:48:15 +02:00
Vedran Pavic
227fab2e42 Adjust CI build timeouts 2018-09-19 00:45:20 +02:00
Vedran Pavic
7f7815d80c Upgrade spring-build-conventions to 0.0.19.RELEASE 2018-09-19 00:01:06 +02:00
Vedran Pavic
002136bad4 Align WebSession#save implementations with API
Closes gh-1135
2018-09-18 23:58:59 +02:00
Vedran Pavic
1085661984 Enable integration tests for JDK 10 and 11 builds
See: #1196, #1197
2018-09-18 20:04:23 +02:00
Vedran Pavic
12bb0741bb Add Java 11 CI build
Closes gh-1197
2018-09-17 18:02:07 +02:00
Vedran Pavic
eecdcb49d9 Remove node designation from JDK 10 build
See gh-1196
2018-09-17 17:59:40 +02:00
Vedran Pavic
3e1a22102d Ensure compatibility with Java 9 and 10
Closes gh-1196
2018-09-16 22:13:56 +02:00
Vedran Pavic
9f6e791e5d Upgrade samples to Spring Boot 2.1.0.M3
Closes gh-1195
2018-09-13 21:04:43 +02:00
Vedran Pavic
efc35eddad Upgrade Gradle to 4.10.1 2018-09-13 20:59:49 +02:00
Vedran Pavic
4c37ec9f4a Update Jenkinsfile to specify node label 2018-09-13 18:08:17 +02:00
Vedran Pavic
1a3da5944d Polish
See gh-1128
2018-09-13 08:55:13 +02:00
Vedran Pavic
5d0775b802 Ensure RedisHttpSessionConfiguration handles events for configured database
At present, RedisHttpSessionConfiguration doesn't take into account database index when handlng events. In situations where multiple apps use Spring Session with same Redis instance, but different database, this results in invalid session events.

This commits improves event handling in RedisHttpSessionConfiguration to ensure currently used database is considered.

Closes gh-1128
2018-09-12 23:07:52 +02:00
Vedran Pavic
603a258172 Upgrade Testcontainers to 1.9.0-rc1 2018-09-11 23:06:10 +02:00
Vedran Pavic
22ebe65931 Next development version 2018-09-10 22:42:32 +02:00
Vedran Pavic
55033bcb64 Release 2.1.0.M3 2018-09-10 22:40:21 +02:00
Vedran Pavic
57955b7d7b Polish
See gh-1111
2018-09-10 17:03:10 +02:00
Vedran Pavic
d5da38f2e0 Upgrade test dependencies 2018-09-10 16:56:08 +02:00
Vedran Pavic
6cc4bcd13d Verify session existence before update in ReactiveRedisOperationsSessionRepository
Currently, ReactiveRedisOperationsSessionRepository#save does not ensure session's existence before executing update. This can result in an invalid session record in Redis, since write use only delta, and in turn to error while retrieving the invalid session record.

This commit adds check for session existence if session is being updated.

Closes gh-1111
2018-09-09 23:55:27 +02:00
Vedran Pavic
dc43f5bd2d Upgrade Spring Security to 5.1.0.RC2
Closes gh-1171
2018-09-07 23:48:18 +02:00
Vedran Pavic
7584cbd54c Upgrade Spring Framework to 5.1.0.RC3
Closes gh-1170
2018-09-07 17:40:18 +02:00
Vedran Pavic
0db1160dc4 Upgrade Reactor to Californium-RC1
Closes gh-1172
2018-09-07 07:48:08 +02:00
Vedran Pavic
10a18366f9 Update integration tests 2018-09-07 07:46:10 +02:00
Vedran Pavic
7ea5e2f3ee Upgrade test dependencies 2018-09-06 21:15:47 +02:00
Vedran Pavic
d3134ad065 Ignore failed rename operation for deleted session
Attempting to change session id for a deleted session currently results in "ERR no such key" error on rename operation of expired key. This commit addressed the problem by ignoring the aforementioned error.

Closes #1137
2018-09-04 23:07:27 +02:00
Vedran Pavic
6208d0298d Upgrade Gradle to 4.10 2018-09-04 21:57:04 +02:00
Vedran Pavic
c031ee278d Add javadoc for RedisOperationsSessionRepository#getSessionRedisOperations
Closes #1175
2018-09-03 23:29:50 +02:00
Vedran Pavic
8267a90fcc Polish contribution
See #1173
2018-09-03 23:28:14 +02:00
Johnny Lim
2113b330a7 Add @since for ReactiveRedisOperationsSR.getSessionRedisOperations() 2018-08-31 10:29:09 -05:00
Vedran Pavic
c4ac68b777 Fix Jenkinsfile 2018-08-27 09:26:55 +02:00
Vedran Pavic
0be2759e68 Fix Jenkinsfile 2018-08-27 08:24:36 +02:00
Vedran Pavic
1181e52bb0 Upgrade spring-build-conventions to 0.0.18.RELEASE 2018-08-24 23:50:23 +02:00
Vedran Pavic
5277d945ed Upgrade samples to Spring Boot 2.1.0.M2
Closes gh-1168
2018-08-22 18:31:30 +02:00
Rob Winch
1fc0162fe9 Fix settings.gradle on Windows
Fixes: gh-1167
2018-08-22 10:23:29 -05:00
Vedran Pavic
9df259b1ae Next development version 2018-08-21 06:34:09 +02:00
344 changed files with 3252 additions and 2202 deletions

View File

@@ -40,5 +40,5 @@ appropriate to the circumstances. Maintainers are obligated to maintain confiden
with regard to the reporter of an incident.
This Code of Conduct is adapted from the
http://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
http://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]
https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]

View File

@@ -10,8 +10,8 @@ By participating, you are expected to uphold this code. Please report unaccepta
== Using GitHub issues
We use GitHub issues to track bugs and enhancements. If you have a general usage question
please ask on http://stackoverflow.com[Stack Overflow]. The Spring Session team and the
broader community monitor the http://stackoverflow.com/tags/spring-session[`spring-session`]
please ask on https://stackoverflow.com[Stack Overflow]. The Spring Session team and the
broader community monitor the https://stackoverflow.com/tags/spring-session[`spring-session`]
tag.
If you are reporting a bug, please help to speed up problem diagnosis by providing as much

60
Jenkinsfile vendored
View File

@@ -11,8 +11,8 @@ currentBuild.result = SUCCESS
try {
parallel check: {
stage('Check') {
timeout(time: 30, unit: 'MINUTES') {
node {
timeout(time: 45, unit: 'MINUTES') {
node('ubuntu1804') {
checkout scm
try {
sh './gradlew clean check --no-daemon --refresh-dependencies'
@@ -22,7 +22,61 @@ try {
throw e
}
finally {
junit '**/build/*-results/*.xml'
junit '**/build/test-results/*/*.xml'
}
}
}
}
},
jdk9: {
stage('JDK 9') {
timeout(time: 45, unit: 'MINUTES') {
node {
checkout scm
try {
withEnv(["JAVA_HOME=${tool 'jdk9'}"]) {
sh './gradlew clean test --no-daemon --refresh-dependencies'
}
}
catch (e) {
currentBuild.result = 'FAILED: jdk9'
throw e
}
}
}
}
},
jdk10: {
stage('JDK 10') {
timeout(time: 45, unit: 'MINUTES') {
node {
checkout scm
try {
withEnv(["JAVA_HOME=${tool 'jdk10'}"]) {
sh './gradlew clean test --no-daemon --refresh-dependencies'
}
}
catch (e) {
currentBuild.result = 'FAILED: jdk10'
throw e
}
}
}
}
},
jdk11: {
stage('JDK 11') {
timeout(time: 45, unit: 'MINUTES') {
node('ubuntu1804') {
checkout scm
try {
withEnv(["JAVA_HOME=${tool 'jdk11'}"]) {
sh './gradlew clean test integrationTest --no-daemon --refresh-dependencies'
}
}
catch (e) {
currentBuild.result = 'FAILED: jdk11'
throw e
}
}
}

View File

@@ -1,7 +1,7 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -193,7 +193,7 @@
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
https://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,

View File

@@ -25,8 +25,8 @@ By participating, you are expected to uphold this code. Please report unaccepta
== Spring Session Project Site
You can find the documentation, issue management, support, samples, and guides for using Spring Session at http://projects.spring.io/spring-session/
You can find the documentation, issue management, support, samples, and guides for using Spring Session at https://projects.spring.io/spring-session/
== License
Spring Session is Open Source software released under the http://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
Spring Session is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].

View File

@@ -1,20 +1,38 @@
buildscript {
ext {
releaseBuild = version.endsWith('RELEASE')
snapshotBuild = version.endsWith('SNAPSHOT')
milestoneBuild = !(releaseBuild || snapshotBuild)
springBootVersion = '2.1.3.RELEASE'
}
repositories {
gradlePluginPortal()
maven { url 'https://repo.spring.io/plugins-release/' }
}
dependencies {
classpath 'io.spring.gradle:spring-build-conventions:0.0.17.RELEASE'
classpath 'io.spring.gradle:spring-build-conventions:0.0.25.RELEASE'
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
}
repositories {
maven { url 'https://repo.spring.io/plugins-release' }
}
}
apply plugin: 'io.spring.convention.root'
group = 'org.springframework.session'
description = 'Spring Session'
ext.releaseBuild = version.endsWith('RELEASE')
ext.snapshotBuild = version.endsWith('SNAPSHOT')
ext.milestoneBuild = !(releaseBuild || snapshotBuild)
gradle.taskGraph.whenReady { graph ->
def jacocoEnabled = graph.allTasks.any { it instanceof JacocoReport }
subprojects {
plugins.withType(JavaPlugin) {
sourceCompatibility = 1.8
}
plugins.withType(JacocoPlugin) {
tasks.withType(Test) {
jacoco.enabled = jacocoEnabled
}
}
}
}

View File

@@ -4,137 +4,141 @@ Rob Winch
This guide describes how to use Spring Session to find sessions by username.
NOTE: The completed guide can be found in the <<findbyusername-sample, findbyusername application>>.
NOTE: You can find the completed guide in the <<findbyusername-sample, findbyusername application>>.
[[findbyusername-assumptions]]
== Assumptions
The guide assumes you have already added Spring Session using the built in Redis configuration support to your application.
The guide assumes you have already added Spring Session to your application by using the built-in Redis configuration support.
The guide also assumes you have already applied Spring Security to your application.
However, we the guide will be somewhat general purpose and can be applied to any technology with minimal changes we will discuss.
However, we the guide is somewhat general purpose and can be applied to any technology with minimal changes, which we discuss later in the guide.
[NOTE]
====
If you need to learn how to add Spring Session to your project, please refer to the listing of link:../#samples[samples and guides]
====
NOTE: If you need to learn how to add Spring Session to your project, see the listing of link:../#samples[samples and guides]
== About the Sample
Our sample is using this feature to invalidate the users session that might have been compromised.
Our sample uses this feature to invalidate the users session that might have been compromised.
Consider the following scenario:
* User goes to library and authenticates to the application
* User goes home and realizes they forgot to log out
* User can log in and terminate the session from the library using clues like the location, created time, last accessed time, etc.
* User goes to library and authenticates to the application.
* User goes home and realizes they forgot to log out.
* User can log in and terminate the session from the library using clues like the location, created time, last accessed time, and so on.
Wouldn't it be nice if we could allow the user to invalidate the session at the library from any device they authenticate with?
Would it not be nice if we could let the user invalidate the session at the library from any device with which they authenticate?
This sample demonstrates how this is possible.
[[findbyindexnamesessionrepository]]
== FindByIndexNameSessionRepository
== Using `FindByIndexNameSessionRepository`
In order to look up a user by their username, you must first choose a `SessionRepository` that implements link:../#api-findbyindexnamesessionrepository[FindByIndexNameSessionRepository].
Our sample application assumes that the Redis support is already setup, so we are ready to go.
To look up a user by their username, you must first choose a `SessionRepository` that implements link:../#api-findbyindexnamesessionrepository[`FindByIndexNameSessionRepository`].
Our sample application assumes that the Redis support is already set up, so we are ready to go.
== Mapping the username
== Mapping the User Name
`FindByIndexNameSessionRepository` can only find a session by the username, if the developer instructs Spring Session what user is associated with the `Session`.
This is done by ensuring that the session attribute with the name `FindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME` is populated with the username.
`FindByIndexNameSessionRepository` can find a session only by the user name if the developer instructs Spring Session what user is associated with the `Session`.
You can do so by ensuring that the session attribute with the name `FindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME` is populated with the username.
Generally, speaking this can be done with the following code immediately after the user authenticates:
Generally speaking, you can do so with the following code immediately after the user authenticates:
====
[source,java,indent=0]
----
include::{docs-test-dir}docs/FindByIndexNameSessionRepositoryTests.java[tags=set-username]
----
====
== Mapping the username with Spring Security
== Mapping the User Name with Spring Security
Since we are using Spring Security, the user name is automatically indexed for us.
This means we will not have to perform any steps to ensure the user name is indexed.
Since we use Spring Security, the user name is automatically indexed for us.
This means we need not perform any steps to ensure the user name is indexed.
== Adding Additional Data to Session
== Adding Additional Data to the Session
It may be nice to associate additional information (i.e. IP Address, the browser, location, etc) to the session.
This makes it easier for the user to know which session they are looking at.
It may be nice to associate additional information (such as the IP Address, the browser, location, and other details) to the session.
Doing so makes it easier for the user to know which session they are looking at.
To do this simply determine which session attribute you want to use and what information you wish to provide.
To do so, determine which session attribute you want to use and what information you wish to provide.
Then create a Java bean that is added as a session attribute.
For example, our sample application includes the location and access type of the session
For example, our sample application includes the location and access type of the session, as the following listing shows:
====
[source,java,indent=0]
----
include::{samples-dir}boot/findbyusername/src/main/java/sample/session/SessionDetails.java[tags=class]
----
====
We then inject that information into the session on each HTTP request using a `SessionDetailsFilter`.
For example:
We then inject that information into the session on each HTTP request using a `SessionDetailsFilter`, as the following example shows:
====
[source,java,indent=0]
----
include::{samples-dir}boot/findbyusername/src/main/java/sample/session/SessionDetailsFilter.java[tags=dofilterinternal]
----
====
We obtain the information we want and then set the `SessionDetails` as an attribute in the `Session`.
When we retrieve the `Session` by username, we can then use the session to access our `SessionDetails` just like any other session attribute.
When we retrieve the `Session` by user name, we can then use the session to access our `SessionDetails` as we would any other session attribute.
[NOTE]
====
You might be wondering at this point why Spring Session does not provide `SessionDetails` functionality out of the box.
The reason, is twofold.
The first is that it is very trivial for applications to implement this themselves.
The second reason is that the information that is populated in the session (and how frequently that information is updated) is highly application dependent.
====
NOTE: You might wonder why Spring Session does not provide `SessionDetails` functionality out of the box.
We have two reasons.
The first reason is that it is very trivial for applications to implement this themselves.
The second reason is that the information that is populated in the session (and how frequently that information is updated) is highly application-dependent.
== Finding sessions for a specific user
We can now find all the sessions for a specific user.
The following example shows how to do so:
====
[source,java,indent=0]
----
include::{samples-dir}boot/findbyusername/src/main/java/sample/mvc/IndexController.java[tags=findbyusername]
----
====
In our instance, we find all sessions for the currently logged in user.
However, this could easily be modified for an administrator to use a form to specify which user to look up.
However, you can modify this for an administrator to use a form to specify which user to look up.
[[findbyusername-sample]]
== findbyusername Sample Application
== `findbyusername` Sample Application
=== Running the findbyusername Sample Application
This section describes how to use the `findbyusername` sample application.
=== Running the `findbyusername` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
----
$ ./gradlew :spring-session-sample-boot-findbyusername:bootRun
----
====
NOTE: For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost.
See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
You should now be able to access the application at http://localhost:8080/
=== Exploring the security Sample Application
Try using the application. Enter the following to log in:
You can now try using the application. Enter the following to log in:
* **Username** _user_
* **Password** _password_
* *Username* _user_
* *Password* _password_
Now click the **Login** button.
Now click the *Login* button.
You should now see a message indicating your are logged in with the user entered previously.
You should also see a listing of active sessions for the currently logged in user.
Let's emulate the flow we discussed in the <<About the Sample>> section
You can emulate the flow we discussed in the <<About the Sample>> section by doing the following:
* Open a new incognito window and navigate to http://localhost:8080/
* Enter the following to log in:
** **Username** _user_
** **Password** _password_
* Terminate your original session
* Refresh the original window and see you are logged out
** *Username* _user_
** *Password* _password_
* Terminate your original session.
* Refresh the original window and see that you are logged out.

View File

@@ -2,15 +2,17 @@
Rob Winch, Vedran Pavić
:toc:
This guide describes how to use Spring Session to transparently leverage a relational database to back a web application's `HttpSession` when using Spring Boot.
This guide describes how to use Spring Session to transparently leverage a relational database to back a web application's `HttpSession` when you use Spring Boot.
NOTE: The completed guide can be found in the <<httpsession-jdbc-boot-sample, httpsession-jdbc-boot sample application>>.
NOTE: You can find the completed guide in the <<httpsession-jdbc-boot-sample, httpsession-jdbc-boot sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
We assume you are working with a working Spring Boot web application.
If you are using Maven, ensure to add the following dependencies:
Before you use Spring Session, you must update your dependencies.
We assume you are working with a working Spring Boot web application.
If you use Maven, you must add the following dependencies:
====
.pom.xml
[source,xml]
[subs="verbatim,attributes"]
@@ -24,8 +26,9 @@ If you are using Maven, ensure to add the following dependencies:
</dependency>
</dependencies>
----
====
Spring Boot provides dependency management for Spring Session modules, so there's no need to explicitly declare dependency version.
Spring Boot provides dependency management for Spring Session modules, so you need not explicitly declare the dependency version.
// tag::config[]
@@ -33,95 +36,106 @@ Spring Boot provides dependency management for Spring Session modules, so there'
== Spring Boot Configuration
After adding the required dependencies, we can create our Spring Boot configuration.
Thanks to first-class auto configuration support, setting up Spring Session backed by a relational database is as simple as adding a single configuration property to your `application.properties`:
Thanks to first-class auto configuration support, setting up Spring Session backed by a relational database is as simple as adding a single configuration property to your `application.properties`.
The following listing shows how to do so:
====
.src/main/resources/application.properties
----
spring.session.store-type=jdbc # Session store type.
----
====
Under the hood, Spring Boot will apply configuration that is equivalent to manually adding `@EnableJdbcHttpSession` annotation.
This creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
Under the hood, Spring Boot applies configuration that is equivalent to manually adding the `@EnableJdbcHttpSession` annotation.
This creates a Spring bean with the name of `springSessionRepositoryFilter`. That bean implements `Filter`.
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
Further customization is possible using `application.properties`:
You can further customize by using `application.properties`.
The following listing shows how to do so:
====
.src/main/resources/application.properties
----
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds will be used.
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds are used.
spring.session.jdbc.initialize-schema=embedded # Database schema initialization mode.
spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema.
spring.session.jdbc.table-name=SPRING_SESSION # Name of the database table used to store sessions.
----
====
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-session[Spring Session] portion of the Spring Boot documentation.
For more information, see the https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-session[Spring Session] portion of the Spring Boot documentation.
[[httpsession-jdbc-boot-configuration]]
== Configuring the DataSource
== Configuring the `DataSource`
Spring Boot automatically creates a `DataSource` that connects Spring Session to an embedded instance of H2 database.
In a production environment you need to ensure to update your configuration to point to your relational database.
For example, you can include the following in your *application.properties*
Spring Boot automatically creates a `DataSource` that connects Spring Session to an embedded instance of an H2 database.
In a production environment, you need to update your configuration to point to your relational database.
For example, you can include the following in your application.properties:
====
.src/main/resources/application.properties
----
spring.datasource.url= # JDBC URL of the database.
spring.datasource.username= # Login username of the database.
spring.datasource.password= # Login password of the database.
----
====
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-configure-datasource[Configure a DataSource] portion of the Spring Boot documentation.
For more information, see the https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-configure-datasource[Configure a DataSource] portion of the Spring Boot documentation.
[[httpsession-jdbc-boot-servlet-configuration]]
== Servlet Container Initialization
Our <<httpsession-jdbc-boot-spring-configuration,Spring Boot Configuration>> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`.
Our <<httpsession-jdbc-boot-spring-configuration,Spring Boot Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, Spring needs to load our `Config` class.
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
Last, we need to ensure that our Servlet Container (that is, Tomcat) uses our `springSessionRepositoryFilter` for every request.
Fortunately, Spring Boot takes care of both of these steps for us.
// end::config[]
[[httpsession-jdbc-boot-sample]]
== httpsession-jdbc-boot Sample Application
== `httpsession-jdbc-boot` Sample Application
The httpsession-jdbc-boot Sample Application demonstrates how to use Spring Session to transparently leverage H2 database to back a web application's `HttpSession` when using Spring Boot.
The httpsession-jdbc-boot Sample Application demonstrates how to use Spring Session to transparently leverage an H2 database to back a web application's `HttpSession` when you use Spring Boot.
[[httpsession-jdbc-boot-running]]
=== Running the httpsession-jdbc-boot Sample Application
=== Running the `httpsession-jdbc-boot` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
====
----
$ ./gradlew :spring-session-sample-boot-jdbc:bootRun
----
====
You should now be able to access the application at http://localhost:8080/
[[httpsession-jdbc-boot-explore]]
=== Exploring the security Sample Application
=== Exploring the Security Sample Application
Try using the application. Enter the following to log in:
You can now try using the application.
To do so, enter the following to log in:
* **Username** _user_
* **Password** _password_
* *Username* _user_
* *Password* _password_
Now click the **Login** button.
You should now see a message indicating your are logged in with the user entered previously.
The user's information is stored in H2 database rather than Tomcat's `HttpSession` implementation.
Now click the *Login* button.
You should now see a message indicating that your are logged in with the user entered previously.
The user's information is stored in the H2 database rather than Tomcat's `HttpSession` implementation.
[[httpsession-jdbc-boot-how]]
=== How does it work?
=== How Does It Work?
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database.
Instead of using Tomcat's `HttpSession`, we persist the values in the H2 database.
Spring Session replaces the `HttpSession` with an implementation that is backed by a relational database.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into H2 database.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`, it is then persisted into the H2 database.
When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
When a new `HttpSession` is created, Spring Session creates a cookie named `SESSION` in your browser. That cookie contains the ID of your session.
You can view the cookies (with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
If you like, you can easily remove the session using H2 web console available at: http://localhost:8080/h2-console/ (use `jdbc:h2:mem:testdb` for JDBC URL)
You can remove the session by using the H2 web console available at: http://localhost:8080/h2-console/ (use `jdbc:h2:mem:testdb` for JDBC URL).
Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated.
Now you can visit the application at http://localhost:8080/ and see that we are no longer authenticated.

View File

@@ -2,15 +2,17 @@
Rob Winch, Vedran Pavić
:toc:
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using Spring Boot.
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when you use Spring Boot.
NOTE: The completed guide can be found in the <<boot-sample, boot sample application>>.
NOTE: You can find the completed guide in the <<boot-sample, boot sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
We assume you are working with a working Spring Boot web application.
If you are using Maven, ensure to add the following dependencies:
Before you use Spring Session, you must ensure your dependencies.
We assume you are working with a working Spring Boot web application.
If you are using Maven, you must add the following dependencies:
====
.pom.xml
[source,xml]
[subs="verbatim,attributes"]
@@ -24,114 +26,131 @@ If you are using Maven, ensure to add the following dependencies:
</dependency>
</dependencies>
----
====
Spring Boot provides dependency management for Spring Session modules, so there's no need to explicitly declare dependency version.
Spring Boot provides dependency management for Spring Session modules, so you need not explicitly declare dependency version.
[[boot-spring-configuration]]
== Spring Boot Configuration
After adding the required dependencies, we can create our Spring Boot configuration.
Thanks to first-class auto configuration support, setting up Spring Session backed by Redis is as simple as adding a single configuration property to your `application.properties`:
Thanks to first-class auto configuration support, setting up Spring Session backed by Redis is as simple as adding a single configuration property to your `application.properties`, as the following listing shows:
====
.src/main/resources/application.properties
----
spring.session.store-type=redis # Session store type.
----
====
Under the hood, Spring Boot will apply configuration that is equivalent to manually adding `@EnableRedisHttpSession` annotation.
This creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
Under the hood, Spring Boot applies configuration that is equivalent to manually adding `@EnableRedisHttpSession` annotation.
This creates a Spring bean with the name of `springSessionRepositoryFilter` that implements `Filter`.
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
Further customization is possible using `application.properties`:
Further customization is possible by using `application.properties`, as the following listing shows:
====
.src/main/resources/application.properties
----
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds will be used.
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds is used.
spring.session.redis.flush-mode=on-save # Sessions flush mode.
spring.session.redis.namespace=spring:session # Namespace for keys used to store sessions.
----
====
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-session[Spring Session] portion of the Spring Boot documentation.
For more information, see the https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-session[Spring Session] portion of the Spring Boot documentation.
[[boot-redis-configuration]]
== Configuring the Redis Connection
Spring Boot automatically creates a `RedisConnectionFactory` that connects Spring Session to a Redis Server on localhost on port 6379 (default port).
In a production environment you need to ensure to update your configuration to point to your Redis server.
For example, you can include the following in your *application.properties*
In a production environment, you need to update your configuration to point to your Redis server.
For example, you can include the following in your application.properties:
====
.src/main/resources/application.properties
----
spring.redis.host=localhost # Redis server host.
spring.redis.password= # Login password of the redis server.
spring.redis.port=6379 # Redis server port.
----
====
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
For more information, see the https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
[[boot-servlet-configuration]]
== Servlet Container Initialization
Our <<boot-spring-configuration,Spring Boot Configuration>> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`.
Our <<boot-spring-configuration,Spring Boot Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, Spring needs to load our `Config` class.
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
Last, we need to ensure that our servlet container (that is, Tomcat) uses our `springSessionRepositoryFilter` for every request.
Fortunately, Spring Boot takes care of both of these steps for us.
[[boot-sample]]
== Boot Sample Application
The Boot Sample Application demonstrates how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using Spring Boot.
The Boot Sample Application demonstrates how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when you use Spring Boot.
[[boot-running]]
=== Running the Boot Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
----
$ ./gradlew :spring-session-sample-boot-redis:bootRun
----
====
NOTE: For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
You should now be able to access the application at http://localhost:8080/
[[boot-explore]]
=== Exploring the security Sample Application
=== Exploring the `security` Sample Application
Try using the application. Enter the following to log in:
Now you can try using the application. Enter the following to log in:
* **Username** _user_
* **Password** _password_
* *Username* _user_
* *Password* _password_
Now click the **Login** button.
Now click the *Login* button.
You should now see a message indicating your are logged in with the user entered previously.
The user's information is stored in Redis rather than Tomcat's `HttpSession` implementation.
[[boot-how]]
=== How does it work?
=== How Does It Work?
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis.
Instead of using Tomcat's `HttpSession`, we persist the values in Redis.
Spring Session replaces the `HttpSession` with an implementation that is backed by Redis.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into Redis.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`, it is then persisted into Redis.
When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
When a new `HttpSession` is created, Spring Session creates a cookie named `SESSION` in your browser.
That cookie contains the ID of your session.
You can view the cookies (with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type:
You can remove the session by using redis-cli.
For example, on a Linux based system you can type the following:
====
----
$ redis-cli keys '*' | xargs redis-cli del
----
====
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
Alternatively, you can also delete the explicit key.
To do so, enter the following into your terminal, being sure to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your `SESSION` cookie:
====
----
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
----
=====
Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated.
Now you can visit the application at http://localhost:8080/ and observe that we are no longer authenticated.

View File

@@ -7,9 +7,8 @@ This guide describes how to use Spring Session to ensure that WebSocket messages
// tag::disclaimer[]
NOTE: Spring Session's WebSocket support only works with Spring's WebSocket support.
Specifically it does not work with using https://www.jcp.org/en/jsr/detail?id=356[JSR-356] directly.
This is due to the fact that JSR-356 does not have a mechanism for intercepting incoming WebSocket messages.
NOTE: Spring Session's WebSocket support works only with Spring's WebSocket support.
Specifically,it does not work with using https://www.jcp.org/en/jsr/detail?id=356[JSR-356] directly, because JSR-356 does not have a mechanism for intercepting incoming WebSocket messages.
// end::disclaimer[]
@@ -17,24 +16,27 @@ This is due to the fact that JSR-356 does not have a mechanism for intercepting
The first step is to integrate Spring Session with the HttpSession. These steps are already outlined in the link:httpsession.html[HttpSession Guide].
Please make sure you have already integrated Spring Session with the HttpSession before proceeding.
Please make sure you have already integrated Spring Session with HttpSession before proceeding.
// tag::config[]
[[websocket-spring-configuration]]
== Spring Configuration
In a typical Spring WebSocket application users would implement `WebSocketMessageBrokerConfigurer`.
In a typical Spring WebSocket application, you would implement `WebSocketMessageBrokerConfigurer`.
For example, the configuration might look something like the following:
====
[source,java]
----
include::{websocketdoc-test-dir}WebSocketConfig.java[tags=class]
----
====
We can easily update our configuration to use Spring Session's WebSocket support.
For example:
We can update our configuration to use Spring Session's WebSocket support.
The following example shows how to do so:
====
.src/main/java/samples/config/WebSocketConfig.java
[source,java]
----
@@ -43,8 +45,9 @@ include::{samples-dir}boot/websocket/src/main/java/sample/config/WebSocketConfig
To hook in the Spring Session support we only need to change two things:
<1> Instead of implementing `WebSocketMessageBrokerConfigurer` we extend `AbstractSessionWebSocketMessageBrokerConfigurer`
<1> Instead of implementing `WebSocketMessageBrokerConfigurer`, we extend `AbstractSessionWebSocketMessageBrokerConfigurer`
<2> We rename the `registerStompEndpoints` method to `configureStompEndpoints`
====
What does `AbstractSessionWebSocketMessageBrokerConfigurer` do behind the scenes?
@@ -52,87 +55,89 @@ What does `AbstractSessionWebSocketMessageBrokerConfigurer` do behind the scenes
This ensures a custom `SessionConnectEvent` is fired that contains the `WebSocketSession`.
The `WebSocketSession` is necessary to terminate any WebSocket connections that are still open when a Spring Session is terminated.
* `SessionRepositoryMessageInterceptor` is added as a `HandshakeInterceptor` to every `StompWebSocketEndpointRegistration`.
This ensures that the Session is added to the WebSocket properties to enable updating the last accessed time.
This ensures that the `Session` is added to the WebSocket properties to enable updating the last accessed time.
* `SessionRepositoryMessageInterceptor` is added as a `ChannelInterceptor` to our inbound `ChannelRegistration`.
This ensures that every time an inbound message is received, that the last accessed time of our Spring Session is updated.
* `WebSocketRegistryListener` is created as a Spring Bean.
This ensures that we have a mapping of all of the Session id to the corresponding WebSocket connections.
* `WebSocketRegistryListener` is created as a Spring bean.
This ensures that we have a mapping of all of the `Session` IDs to the corresponding WebSocket connections.
By maintaining this mapping, we can close all the WebSocket connections when a Spring Session (HttpSession) is terminated.
// end::config[]
[[websocket-sample]]
== websocket Sample Application
== `websocket` Sample Application
The websocket sample application demonstrates how to use Spring Session with WebSockets.
The `websocket` sample application demonstrates how to use Spring Session with WebSockets.
=== Running the websocket Sample Application
=== Running the `websocket` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[TIP]
====
For the purposes of testing session expiration, you may want to change the session expiration to be 1 minute (default is 30 minutes) by adding the following configuration property starting before the application:
----
$ ./gradlew :spring-session-sample-boot-websocket:bootRun
----
====
[TIP]
=====
For the purposes of testing session expiration, you may want to change the session expiration to be 1 minute (the default is 30 minutes) by adding the following configuration property before starting the application:
====
.src/main/resources/application.properties
----
server.servlet.session.timeout=1m # Session timeout. If a duration suffix is not specified, seconds will be used.
----
====
=====
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
NOTE: For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
----
$ ./gradlew :spring-session-sample-boot-websocket:bootRun
----
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost.
See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
You should now be able to access the application at http://localhost:8080/
=== Exploring the websocket Sample Application
=== Exploring the `websocket` Sample Application
Try using the application. Authenticate with the following information:
Now you can try using the application. Authenticate with the following information:
* **Username** _rob_
* **Password** _password_
* *Username* _rob_
* *Password* _password_
Now click the **Login** button. You should now be authenticated as the user **rob**.
Now click the *Login* button. You should now be authenticated as the user **rob**.
Open an incognito window and access http://localhost:8080/
You will be prompted with a log in form. Authenticate with the following information:
You are prompted with a login form. Authenticate with the following information:
* **Username** _luke_
* **Password** _password_
* *Username* _luke_
* *Password* _password_
Now send a message from *rob* to *luke*. The message should appear.
Now send a message from rob to luke. The message should appear.
Wait for two minutes and try sending a message from *rob* to *luke* again.
You will see that the message is no longer sent.
Wait for two minutes and try sending a message from rob to luke again.
You can see that the message is no longer sent.
[NOTE]
.Why two minutes?
====
Spring Session will expire in 60 seconds, but the notification from Redis is not guaranteed to happen within 60 seconds.
Spring Session expires in 60 seconds, but the notification from Redis is not guaranteed to happen within 60 seconds.
To ensure the socket is closed in a reasonable amount of time, Spring Session runs a background task every minute at 00 seconds that forcibly cleans up any expired sessions.
This means you will need to wait at most two minutes before the WebSocket connection is terminated.
This means you need to wait at most two minutes before the WebSocket connection is terminated.
====
Try accessing http://localhost:8080/
You will be prompted to authenticate again.
You can now try accessing http://localhost:8080/
You are prompted to authenticate again.
This demonstrates that the session properly expires.
Now repeat the same exercise, but instead of waiting two minutes send a message from *each* of the users every 30 seconds.
You will see that the messages continue to be sent.
Now repeat the same exercise, but instead of waiting two minutes, send a message from each of the users every 30 seconds.
You can see that the messages continue to be sent.
Try accessing http://localhost:8080/
You will not be prompted to authenticate again.
You are not prompted to authenticate again.
This demonstrates the session is kept alive.
NOTE: Only messages sent from a user keep the session alive.
This is because only messages coming from a user imply user activity.
Messages received do not imply activity and thus do not renew the session expiration.
Received messages do not imply activity and, thus, do not renew the session expiration.

View File

@@ -2,17 +2,19 @@
Eric Helgeson
:toc:
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using Grails 3.1
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when you use Grails 3.1
NOTE: Grails 3.1 is based off spring boot 1.3 so much of the advanced configuration and options can be found in the boot docs as well.
NOTE: Grails 3.1 is based off spring boot 1.3, so much of the advanced configuration and options can be found in the Boot docs as well.
NOTE: The completed guide can be found in the <<grails3-sample, Grails 3 sample application>>.
NOTE: You can find the completed guid in the <<grails3-sample, Grails 3 sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
We assume you are working with a working Grails 3.1 web profile.
Add the following dependencies:
Before you use Spring Session, you must update your dependencies.
We assume you are working with a working Grails 3.1 web profile.
You must add the following dependencies:
====
.build.gradle
[source,groovy]
[subs="verbatim,attributes"]
@@ -22,11 +24,13 @@ dependencies {
compile 'org.springframework.session:spring-session:{spring-session-version}'
}
----
====
ifeval::["{version-snapshot}" == "true"]
Since We are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
Ensure you have the following in your pom.xml:
Since we use a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
You must have the following in your build.gradle:
====
.build.gradle
[source,groovy]
----
@@ -36,12 +40,14 @@ repositories {
}
}
----
====
endif::[]
ifeval::["{version-milestone}" == "true"]
Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository.
Ensure you have the following in your pom.xml:
Since we use a Milestone version, we need to add the Spring Milestone Maven Repository.
You must have the following in your build.gradle:
====
.build.gradle
[source,groovy]
----
@@ -51,6 +57,7 @@ repositories {
}
}
----
====
endif::[]
[[grails3-redis-configuration]]
@@ -58,8 +65,9 @@ endif::[]
Spring Boot automatically creates a `RedisConnectionFactory` that connects Spring Session to a Redis Server on localhost on port 6379 (default port).
In a production environment you need to ensure to update your configuration to point to your Redis server.
For example, you can include the following in your *application.yml*
For example, you can include the following in your application.yml:
====
.grails-app/conf/application.yml
[source,yml]
----
@@ -69,8 +77,9 @@ spring:
password: secret
port: 6397
----
====
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
For more information, see the https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
[[grails3-sample]]
== Grails 3 Sample Application
@@ -82,52 +91,61 @@ The Grails 3 Sample Application demonstrates how to use Spring Session to transp
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
----
$ ./gradlew :spring-session-sample-misc-grails3:bootRun
----
NOTE:For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost.
See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
You should now be able to access the application at http://localhost:8080/test/index
[[grails3-explore]]
=== Exploring the security Sample Application
=== Exploring the `security` Sample Application
Try using the application. Enter the following to log in:
You can now try using the application. Enter the following to log in:
* **Username** _user_
* **Password** _password_
* *Username* _user_
* *Password* _password_
Now click the **Login** button.
You should now see a message indicating your are logged in with the user entered previously.
Now click the *Login* button.
You should now see a message indicating that your are logged in with the user entered previously.
The user's information is stored in Redis rather than Tomcat's `HttpSession` implementation.
[[grails3-how]]
=== How does it work?
=== How Does It Work?
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis.
Instead of using Tomcat's `HttpSession`, we persist the values in Redis.
Spring Session replaces the `HttpSession` with an implementation that is backed by Redis.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into Redis.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`, it is then persisted into Redis.
When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
When a new `HttpSession` is created, Spring Session creates a cookie named `SESSION` in your browser.
That cookie contains the ID of your session.
You can view the cookies (with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type:
You can remove the session by using redis-cli.
For example, on a Linux based system you can type the following:
====
----
$ redis-cli keys '*' | xargs redis-cli del
----
====
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
Alternatively, you can also delete the explicit key.
To do so, enter the following into your terminal, being sure to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your `SESSION` cookie:
====
----
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
----
====
Now visit the application at http://localhost:8080/test/index and observe that we are no longer authenticated.
Now you can visit the application at http://localhost:8080/test/index and see that we are no longer authenticated.
NOTE: Spring Session will not work with grails flash scope without additional work. +
See this answer for an explanation: https://stackoverflow.com/a/43311427
NOTE: Spring Session does not work with Grails flash scope without additional work.
See https://stackoverflow.com/a/43311427 for an explanation.

View File

@@ -3,100 +3,95 @@ Rob Winch
:toc:
This guide describes how to configure Spring Session to use custom cookies with Java Configuration.
The guide assumes you have already link:./httpsession.html[setup Spring Session in your project].
The guide assumes you have already link:./httpsession.html[set up Spring Session in your project].
NOTE: The completed guide can be found in the <<custom-cookie-sample, Custom Cookie sample application>>.
NOTE: You can find the completed guide in the <<custom-cookie-sample, Custom Cookie sample application>>.
[[custom-cookie-spring-configuration]]
== Spring Java Configuration
Once you have setup Spring Session you can easily customize how the session cookie is written by exposing a `CookieSerializer` as a Spring Bean.
Out of the box, Spring Session comes with `DefaultCookieSerializer`.
Simply exposing the `DefaultCookieSerializer` as a Spring Bean will augment the existing configuration when using configurations like `@EnableRedisHttpSession`.
You can find an example of customizing Spring Session's cookie below:
Once you have set up Spring Session, you can customize how the session cookie is written by exposing a `CookieSerializer` as a Spring bean.
Spring Session comes with `DefaultCookieSerializer`.
Exposing the `DefaultCookieSerializer` as a Spring bean augments the existing configuration when you use configurations like `@EnableRedisHttpSession`.
The following example shows how to customize Spring Session's cookie:
====
[source,java]
----
include::{samples-dir}javaconfig/custom-cookie/src/main/java/sample/Config.java[tags=cookie-serializer]
----
<1> We customize the name of the cookie to be JSESSIONID
<2> We customize the path of the cookie to be "/" (rather than the default of the context root)
<3> We customize the domain name pattern (a regular expression) to be `^.+?\\.(\\w+\\.[a-z]+)$`
<1> We customize the name of the cookie to be `JSESSIONID`.
<2> We customize the path of the cookie to be `/` (rather than the default of the context root).
<3> We customize the domain name pattern (a regular expression) to be `^.+?\\.(\\w+\\.[a-z]+)$`.
This allows sharing a session across domains and applications.
If the regular expression does not match, no domain is set and the existing domain will be used.
If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] will be used as the domain.
This means that a request to https://child.example.com will set the domain to example.com.
However, a request to http://localhost:8080/ or http://192.168.1.100:8080/ will leave the cookie unset and thus still work in development without any changes necessary for production.
If the regular expression does not match, no domain is set and the existing domain is used.
If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] is used as the domain.
This means that a request to https://child.example.com sets the domain to `example.com`.
However, a request to http://localhost:8080/ or https://192.168.1.100:8080/ leaves the cookie unset and, thus, still works in development without any changes being necessary for production.
====
[WARNING]
====
It is important to note that users should only match on valid domain characters since the domain name is reflected in the response.
This is prevent a malicious user from performing attacks like https://en.wikipedia.org/wiki/HTTP_response_splitting[HTTP Response Splitting].
====
WARNING: You should only match on valid domain characters, since the domain name is reflected in the response.
Doing so prevents a malicious user from performing such attacks as https://en.wikipedia.org/wiki/HTTP_response_splitting[HTTP Response Splitting].
[[custom-cookie-options]]
== Configuration Options
The configuration options available are:
The following configuration options are available:
* `cookieName` - the name of the cookie to use
Default "SESSION"
* `useSecureCookie` - specify if a secure cookie be used
Default use value of `HttpServletRequest.isSecure()` at the time of creation.
* `cookiePath` - the path of the cookie
Default is context root
* `cookieMaxAge` - specifies the max age of the cookie to be set at the time the session is created.
Default is -1 which indicates the cookie will be removed when the browser is closed.
* `jvmRoute` - specifies a suffix to be appended to the session id and included in the cookie.
* `cookieName`: The name of the cookie to use.
Default: `SESSION`.
* `useSecureCookie`: Specifies whether a secure cookie should be used.
Default: Use the value of `HttpServletRequest.isSecure()` at the time of creation.
* `cookiePath`: The path of the cookie.
Default: The context root.
* `cookieMaxAge`: Specifies the max age of the cookie to be set at the time the session is created.
Default: `-1`, which indicates the cookie should be removed when the browser is closed.
* `jvmRoute`: Specifies a suffix to be appended to the session ID and included in the cookie.
Used to identify which JVM to route to for session affinity.
With some implementations (i.e. Redis) this provides no performance benefit.
However, this can help with tracing logs of a particular user.
* `domainName` - allows specifying a specific domain name to be used for the cookie.
This option is simple to understand, but will likely require a different configuration between development and production environments.
See domainNamePattern as an alternative.
* `domainNamePattern` - a case insensitive pattern used to extract the domain name from the `HttpServletRequest#getServerName()`.
The pattern should provide a single grouping used to extract the value of the cookie domain.
If the regular expression does not match, no domain is set and the existing domain will be used.
If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] will be used as the domain.
With some implementations (that is, Redis) this option provides no performance benefit.
However, it can help with tracing logs of a particular user.
* `domainName`: Allows specifying a specific domain name to be used for the cookie.
This option is simple to understand but often requires a different configuration between development and production environments.
See `domainNamePattern` as an alternative.
* `domainNamePattern`: A case-insensitive pattern used to extract the domain name from the `HttpServletRequest#getServerName()`.
The pattern should provide a single grouping that is used to extract the value of the cookie domain.
If the regular expression does not match, no domain is set and the existing domain is used.
If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] is used as the domain.
[WARNING]
====
It is important to note that users should only match on valid domain characters since the domain name is reflected in the response.
This is prevent a malicious user from performing attacks like https://en.wikipedia.org/wiki/HTTP_response_splitting[HTTP Response Splitting].
====
WARNING: You should only match on valid domain characters, since the domain name is reflected in the response.
Doing so prevents a malicious user from performing such attacks as https://en.wikipedia.org/wiki/HTTP_response_splitting[HTTP Response Splitting].
[[custom-cookie-sample]]
== custom-cookie Sample Application
== `custom-cookie` Sample Application
This section describes how to work with the `custom-cookie` sample application.
=== Running the custom-cookie Sample Application
=== Running the `custom-cookie` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
----
$ ./gradlew :spring-session-sample-javaconfig-custom-cookie:tomcatRun
----
====
NOTE: For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
You should now be able to access the application at http://localhost:8080/
=== Exploring the custom-cookie Sample Application
=== Exploring the `custom-cookie` Sample Application
Try using the application. Fill out the form with the following information:
Now you can use the application. Fill out the form with the following information:
* **Attribute Name:** _username_
* **Attribute Value:** _rob_
* *Attribute Name:* _username_
* *Attribute Value:* _rob_
Now click the **Set Attribute** button.
Now click the *Set Attribute* button.
You should now see the values displayed in the table.
If you look at the cookies for the application, you can see the cookie is saved to the custom name of JSESSIONID
If you look at the cookies for the application, you can see the cookie is saved to the custom name of `JSESSIONID`.

View File

@@ -2,15 +2,17 @@
Tommy Ludwig; Rob Winch
:toc:
This guide describes how to use Spring Session along with Spring Security using Hazelcast as your data store.
It assumes you have already applied Spring Security to your application.
This guide describes how to use Spring Session along with Spring Security when you use Hazelcast as your data store.
It assumes that you have already applied Spring Security to your application.
NOTE: The completed guide can be found in the <<hazelcast-spring-security-sample, Hazelcast Spring Security sample application>>.
NOTE: You cand find the completed guide in the <<hazelcast-spring-security-sample, Hazelcast Spring Security sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
If you are using Maven, ensure to add the following dependencies:
Before you use Spring Session, you must update your dependencies.
If you use Maven, you must add the following dependencies:
====
.pom.xml
[source,xml]
[subs="verbatim,attributes"]
@@ -30,11 +32,13 @@ If you are using Maven, ensure to add the following dependencies:
</dependency>
</dependencies>
----
====
ifeval::["{version-snapshot}" == "true"]
Since We are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a SNAPSHOT version, we need to add the Spring Snapshot Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -48,12 +52,14 @@ Ensure you have the following in your pom.xml:
</repository>
</repositories>
----
====
endif::[]
ifeval::["{version-milestone}" == "true"]
Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a Milestone version, we need to add the Spring Milestone Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -62,6 +68,7 @@ Ensure you have the following in your pom.xml:
<url>https://repo.spring.io/libs-milestone</url>
</repository>
----
====
endif::[]
// tag::config[]
@@ -70,126 +77,146 @@ endif::[]
== Spring Configuration
After adding the required dependencies, we can create our Spring configuration.
The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
Add the following Spring Configuration:
The Spring configuration is responsible for creating a servlet filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
To do so, add the following Spring Configuration:
====
[source,java]
----
include::{docs-test-dir}docs/http/HazelcastHttpSessionConfig.java[tags=config]
----
<1> The `@EnableHazelcastHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance Spring Session is backed by Hazelcast.
<2> In order to support retrieval of sessions by principal name index, appropriate `ValueExtractor` needs to be registered.
<1> The `@EnableHazelcastHttpSession` annotation creates a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance, Spring Session is backed by Hazelcast.
<2> In order to support retrieval of sessions by principal name index, an appropriate `ValueExtractor` needs to be registered.
Spring Session provides `PrincipalNameExtractor` for this purpose.
<3> We create a `HazelcastInstance` that connects Spring Session to Hazelcast.
By default, an embedded instance of Hazelcast is started and connected to by the application.
For more information on configuring Hazelcast, refer to the http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#hazelcast-configuration[reference documentation].
By default, the application starts and connects to an embedded instance of Hazelcast.
For more information on configuring Hazelcast, see the https://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#hazelcast-configuration[reference documentation].
====
== Servlet Container Initialization
Our <<security-spring-configuration,Spring Configuration>> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`.
Our <<security-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, Spring needs to load our `SessionConfig` class.
Since our application is already loading Spring configuration using our `SecurityInitializer` class, we can simply add our `SessionConfig` class to it.
Since our application is already loading Spring configuration by using our `SecurityInitializer` class, we can add our `SessionConfig` class to it.
The following listing shows how to do so:
====
.src/main/java/sample/SecurityInitializer.java
[source,java]
----
include::{samples-dir}javaconfig/hazelcast/src/main/java/sample/SecurityInitializer.java[tags=class]
----
====
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
Last, we need to ensure that our Servlet Container (that is, Tomcat) uses our `springSessionRepositoryFilter` for every request.
It is extremely important that Spring Session's `springSessionRepositoryFilter` is invoked before Spring Security's `springSecurityFilterChain`.
This ensures that the `HttpSession` that Spring Security uses is backed by Spring Session.
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` that makes this extremely easy.
You can find an example below:
Doing so ensures that the `HttpSession` that Spring Security uses is backed by Spring Session.
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` that makes this doing so easy.
The following example shows how to do so:
====
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/hazelcast/src/main/java/sample/Initializer.java[tags=class]
----
====
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
NOTE: The name of our class (`Initializer`) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
By extending `AbstractHttpSessionApplicationInitializer` we ensure that the Spring Bean by the name `springSessionRepositoryFilter` is registered with our Servlet Container for every request before Spring Security's `springSecurityFilterChain`.
By extending `AbstractHttpSessionApplicationInitializer`, we ensure that the Spring Bean named `springSessionRepositoryFilter` is registered with our servlet container for every request before Spring Security's `springSecurityFilterChain`.
// end::config[]
[[hazelcast-spring-security-sample]]
== Hazelcast Spring Security Sample Application
This section describes how to work with the Hazelcast Spring Security sample application.
=== Running the Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[NOTE]
====
Hazelcast will run in embedded mode with your application by default, but if you want to connect
to a stand alone instance instead, you can configure it by following the instructions in the
http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#hazelcast-configuration[reference documentation].
====
----
$ ./gradlew :spring-session-sample-javaconfig-hazelcast:tomcatRun
----
====
NOTE: By default, Hazelcast runs in embedded mode with your application.
However, if you want to connect to a standalone instance instead, you can configure it by following the instructions in the https://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#hazelcast-configuration[reference documentation].
You should now be able to access the application at http://localhost:8080/
=== Exploring the security Sample Application
=== Exploring the Security Sample Application
Try using the application. Enter the following to log in:
You can now try using the application.
To do so, enter the following to log in:
* **Username** _user_
* **Password** _password_
* *Username* _user_
* *Password* _password_
Now click the **Login** button.
You should now see a message indicating your are logged in with the user entered previously.
Now click the *Login* button.
You should now see a message indicating that your are logged in with the user entered previously.
The user's information is stored in Hazelcast rather than Tomcat's `HttpSession` implementation.
=== How does it work?
=== How Does It Work?
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Hazelcast.
Instead of using Tomcat's `HttpSession`, we persist the values in Hazelcast.
Spring Session replaces the `HttpSession` with an implementation that is backed by a `Map` in Hazelcast.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into Hazelcast.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`, it is then persisted into Hazelcast.
When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
When a new `HttpSession` is created, Spring Session creates a cookie named `SESSION` in your browser. That cookie contains the ID of your session.
You can view the cookies (with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
=== Interact with the data store
=== Interacting with the Data Store
If you like, you can remove the session using http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#hazelcast-java-client[a Java client],
http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#other-client-implementations[one of the other clients], or the
http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#management-center[management center].
You can remove the session by using https://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#hazelcast-java-client[a Java client],
https://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#other-client-implementations[one of the other clients], or the
https://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#management-center[management center].
==== Using the console
==== Using the Console
For example, using the management center console after connecting to your Hazelcast node:
For example, to remove the session by using the management center console after connecting to your Hazelcast node, run the following commands:
====
----
default> ns spring:session:sessions
spring:session:sessions> m.clear
----
====
TIP: The Hazelcast documentation has instructions for http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#executing-console-commands[the console].
TIP: The Hazelcast documentation has instructions for https://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#executing-console-commands[the console].
Alternatively, you can also delete the explicit key. Enter the following into the console ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
Alternatively, you can also delete the explicit key. Enter the following into the console, being sure to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your `SESSION` cookie:
====
----
spring:session:sessions> m.remove 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
----
====
Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated.
==== Using the REST API
As described in the other clients section of the documentation, there is a
http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#rest-client[REST API]
As described in the section of the documentation that cover other clients, there is a
https://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#rest-client[REST API]
provided by the Hazelcast node(s).
For example, you could delete an individual key as follows (replacing `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie):
For example, you could delete an individual key as follows (being sure to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie):
====
----
$ curl -v -X DELETE http://localhost:xxxxx/hazelcast/rest/maps/spring:session:sessions/7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
----
====
TIP: The port number of the Hazelcast node will be printed to the console on startup. Replace `xxxxx` above with the port number.
TIP: The port number of the Hazelcast node is printed to the console on startup. Replace `xxxxx` with the port number.
Now observe that you are no longer authenticated with this session.
Now you can see that you are no longer authenticated with this session.

View File

@@ -4,12 +4,14 @@ Rob Winch, Vedran Pavić
This guide describes how to use Spring Session to transparently leverage a relational database to back a web application's `HttpSession` with Java Configuration.
NOTE: The completed guide can be found in the <<httpsession-jdbc-sample, httpsession-jdbc sample application>>.
NOTE: You can find the completed guide in the <<httpsession-jdbc-sample, httpsession-jdbc sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
If you are using Maven, ensure to add the following dependencies:
Before you use Spring Session, you must update your dependencies.
If you use Maven, you must add the following dependencies:
====
.pom.xml
[source,xml]
[subs="verbatim,attributes"]
@@ -30,11 +32,13 @@ If you are using Maven, ensure to add the following dependencies:
</dependency>
</dependencies>
----
====
ifeval::["{version-snapshot}" == "true"]
Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
Ensure you have the following in your pom.xml:
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -48,12 +52,14 @@ Ensure you have the following in your pom.xml:
</repository>
</repositories>
----
====
endif::[]
ifeval::["{version-milestone}" == "true"]
Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a Milestone version, we need to add the Spring Milestone Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -62,6 +68,7 @@ Ensure you have the following in your pom.xml:
<url>https://repo.spring.io/libs-milestone</url>
</repository>
----
====
endif::[]
// tag::config[]
@@ -71,82 +78,95 @@ endif::[]
After adding the required dependencies, we can create our Spring configuration.
The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
Add the following Spring Configuration:
To do so, add the following Spring Configuration:
====
[source,java]
----
include::{samples-dir}javaconfig/jdbc/src/main/java/sample/Config.java[tags=class]
----
<1> The `@EnableJdbcHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance Spring Session is backed by a relational database.
<2> We create a `dataSource` that connects Spring Session to an embedded instance of H2 database.
We configure the H2 database to create database tables using the SQL script which is included in Spring Session.
<1> The `@EnableJdbcHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter`.
That bean implements `Filter`.
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance, Spring Session is backed by a relational database.
<2> We create a `dataSource` that connects Spring Session to an embedded instance of an H2 database.
We configure the H2 database to create database tables by using the SQL script that is included in Spring Session.
<3> We create a `transactionManager` that manages transactions for previously configured `dataSource`.
====
For additional information on how to configure data access related concerns, please refer to the https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/data-access.html[Spring Framework Reference Documentation].
For additional information on how to configure data access related concerns, see the https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/data-access.html[Spring Framework Reference Documentation].
== Java Servlet Container Initialization
Our <<httpsession-spring-configuration,Spring Configuration>> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`.
Our <<httpsession-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, Spring needs to load our `Config` class.
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` both of these steps extremely easy.
You can find an example below:
Last, we need to ensure that our Servlet Container (that is, Tomcat) uses our `springSessionRepositoryFilter` for every request.
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` to make both of these steps easy.
The following example shows how to do so:
====
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/jdbc/src/main/java/sample/Initializer.java[tags=class]
----
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
NOTE: The name of our class (Initializer) does not matter.
What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
<1> The first step is to extend `AbstractHttpSessionApplicationInitializer`.
This ensures that the Spring Bean by the name `springSessionRepositoryFilter` is registered with our Servlet Container for every request.
<2> `AbstractHttpSessionApplicationInitializer` also provides a mechanism to easily ensure Spring loads our `Config`.
Doing so ensures that the Spring bean named `springSessionRepositoryFilter` is registered with our Servlet Container for every request.
<2> `AbstractHttpSessionApplicationInitializer` also provides a mechanism to ensure Spring loads our `Config`.
====
// end::config[]
[[httpsession-jdbc-sample]]
== httpsession-jdbc Sample Application
== `httpsession-jdbc` Sample Application
=== Running the httpsession-jdbc Sample Application
This section describes how to work with the `httpsession-jdbc` Sample Application.
=== Running the `httpsession-jdbc` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
====
----
$ ./gradlew :spring-session-sample-javaconfig-jdbc:tomcatRun
----
====
You should now be able to access the application at http://localhost:8080/
=== Exploring the httpsession-jdbc Sample Application
=== Exploring the `httpsession-jdbc` Sample Application
Try using the application. Fill out the form with the following information:
Now you can try using the application. To do so, fill out the form with the following information:
* **Attribute Name:** _username_
* **Attribute Value:** _rob_
* *Attribute Name:* _username_
* *Attribute Value:* _rob_
Now click the **Set Attribute** button. You should now see the values displayed in the table.
Now click the *Set Attribute* button. You should now see the values displayed in the table.
=== How does it work?
=== How Does It Work?
We interact with the standard `HttpSession` in the `SessionServlet` shown below:
We interact with the standard `HttpSession` in the `SessionServlet` shown in the following listing:
====
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}javaconfig/jdbc/src/main/java/sample/SessionServlet.java[tags=class]
----
====
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database.
Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
Instead of using Tomcat's `HttpSession`, we persist the values in H2 database.
Spring Session creates a cookie named `SESSION` in your browser.
That cookie contains the ID of your session.
You can view the cookies (with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
If you like, you can easily remove the session using H2 web console available at: http://localhost:8080/h2-console/ (use `jdbc:h2:mem:testdb` for JDBC URL)
If you like, you can remove the session by using the H2 web console available at: http://localhost:8080/h2-console/ (use `jdbc:h2:mem:testdb` for JDBC URL).
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
Now you can visit the application at http://localhost:8080/ and see that the attribute we added is no longer displayed.

View File

@@ -1,15 +1,17 @@
= Spring Session - HttpSession (Quick Start)
Rob Winch
:toc:
:version-snapshot: true
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` with Java Configuration.
NOTE: The completed guide can be found in the <<httpsession-sample, httpsession sample application>>.
NOTE: You can find the completed guide in the <<httpsession-sample, httpsession sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
If you are using Maven, ensure to add the following dependencies:
Before you use Spring Session, you must update your dependencies.
If you are using Maven, you must add the following dependencies:
====
.pom.xml
[source,xml]
[subs="verbatim,attributes"]
@@ -35,11 +37,13 @@ If you are using Maven, ensure to add the following dependencies:
</dependency>
</dependencies>
----
====
ifeval::["{version-snapshot}" == "true"]
Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
Ensure you have the following in your pom.xml:
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -53,12 +57,14 @@ Ensure you have the following in your pom.xml:
</repository>
</repositories>
----
====
endif::[]
ifeval::["{version-milestone}" == "true"]
Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -67,6 +73,7 @@ Ensure you have the following in your pom.xml:
<url>https://repo.spring.io/libs-milestone</url>
</repository>
----
====
endif::[]
// tag::config[]
@@ -75,20 +82,22 @@ endif::[]
== Spring Java Configuration
After adding the required dependencies, we can create our Spring configuration.
The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
Add the following Spring Configuration:
The Spring configuration is responsible for creating a servlet filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
To do so, add the following Spring Configuration:
====
[source,java]
----
include::{samples-dir}javaconfig/redis/src/main/java/sample/Config.java[tags=class]
----
<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance Spring Session is backed by Redis.
<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements `Filter`.
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance, Spring Session is backed by Redis.
<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server.
We configure the connection to connect to localhost on the default port (6379)
For more information on configuring Spring Data Redis, refer to the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
We configure the connection to connect to localhost on the default port (6379).
For more information on configuring Spring Data Redis, see the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
====
== Java Servlet Container Initialization
@@ -96,22 +105,24 @@ Our <<httpsession-spring-configuration,Spring Configuration>> created a Spring B
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, Spring needs to load our `Config` class.
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` both of these steps extremely easy.
You can find an example below:
Last, we need to ensure that our Servlet Container (that is, Tomcat) uses our `springSessionRepositoryFilter` for every request.
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` to make both of these steps easy.
The following shows an example:
====
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/redis/src/main/java/sample/Initializer.java[tags=class]
----
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
NOTE: The name of our class (`Initializer`) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
<1> The first step is to extend `AbstractHttpSessionApplicationInitializer`.
This ensures that the Spring Bean by the name `springSessionRepositoryFilter` is registered with our Servlet Container for every request.
<2> `AbstractHttpSessionApplicationInitializer` also provides a mechanism to easily ensure Spring loads our `Config`.
Doing so ensures that the Spring Bean by the name of `springSessionRepositoryFilter` is registered with our Servlet Container for every request.
<2> `AbstractHttpSessionApplicationInitializer` also provides a mechanism to ensure Spring loads our `Config`.
====
// end::config[]
[[httpsession-sample]]
@@ -119,54 +130,66 @@ This ensures that the Spring Bean by the name `springSessionRepositoryFilter` is
=== Running the httpsession Sample Application
=== Running the `httpsession` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
----
$ ./gradlew :spring-session-sample-javaconfig-redis:tomcatRun
----
====
NOTE: For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost.
See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
You should now be able to access the application at http://localhost:8080/
=== Exploring the httpsession Sample Application
=== Exploring the `httpsession` Sample Application
Try using the application. Fill out the form with the following information:
Now you can try to use the application. To do so, fill out the form with the following information:
* **Attribute Name:** _username_
* **Attribute Value:** _rob_
* *Attribute Name:* _username_
* *Attribute Value:* _rob_
Now click the **Set Attribute** button. You should now see the values displayed in the table.
Now click the *Set Attribute* button. You should now see the values displayed in the table.
=== How does it work?
=== How Does It Work?
We interact with the standard `HttpSession` in the `SessionServlet` shown below:
We interact with the standard `HttpSession` in the `SessionServlet` shown in the following listing:
====
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}javaconfig/redis/src/main/java/sample/SessionServlet.java[tags=class]
----
====
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis.
Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
Instead of using Tomcat's `HttpSession`, we persist the values in Redis.
Spring Session creates a cookie named `SESSION` in your browser.
That cookie contains the ID of your session.
You can view the cookies (with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type:
You can remove the session by using redis-cli.
For example, on a Linux based system you can type the following:
====
----
$ redis-cli keys '*' | xargs redis-cli del
----
====
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
Alternatively, you can also delete the explicit key. Enter the following into your terminal, being sure to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
====
----
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
----
====
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
Now you can visit the application at http://localhost:8080/ and see that the attribute we added is no longer displayed.

View File

@@ -2,14 +2,16 @@
Rob Winch
:toc:
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using REST endpoints.
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when you use REST endpoints.
NOTE: The completed guide can be found in the <<rest-sample, rest sample application>>.
NOTE: You can find the completed guide in the <<rest-sample, rest sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
If you are using Maven, ensure to add the following dependencies:
Before you use Spring Session, you must update your dependencies.
If you use Maven, you must add the following dependencies:
====
.pom.xml
[source,xml]
[subs="verbatim,attributes"]
@@ -35,11 +37,13 @@ If you are using Maven, ensure to add the following dependencies:
</dependency>
</dependencies>
----
====
ifeval::["{version-snapshot}" == "true"]
Since We are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -53,12 +57,14 @@ Ensure you have the following in your pom.xml:
</repository>
</repositories>
----
====
endif::[]
ifeval::["{version-milestone}" == "true"]
Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a Milestone version, we need to add the Spring Milestone Maven Repository.
You msut have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -67,6 +73,7 @@ Ensure you have the following in your pom.xml:
<url>https://repo.spring.io/libs-milestone</url>
</repository>
----
====
endif::[]
// tag::config[]
@@ -75,83 +82,103 @@ endif::[]
== Spring Configuration
After adding the required dependencies, we can create our Spring configuration.
The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
Add the following Spring Configuration:
The Spring configuration is responsible for creating a servlet filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
To do so, add the following Spring Configuration:
====
[source,java]
----
include::{samples-dir}javaconfig/rest/src/main/java/sample/HttpSessionConfig.java[tags=class]
----
<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements `Filter`.
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance Spring Session is backed by Redis.
<1> The `@EnableRedisHttpSession` annotation creates a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance, Spring Session is backed by Redis.
<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server.
We configure the connection to connect to localhost on the default port (6379)
For more information on configuring Spring Data Redis, refer to the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
We configure the connection to connect to localhost on the default port (6379).
For more information on configuring Spring Data Redis, see the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
<3> We customize Spring Session's HttpSession integration to use HTTP headers to convey the current session information instead of cookies.
====
== Servlet Container Initialization
Our <<rest-spring-configuration,Spring Configuration>> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`.
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, Spring needs to load our `Config` class. We provide the configuration in our Spring `MvcInitializer` as shown below:
In order for our `Filter` to do its magic, Spring needs to load our `Config` class.
We provide the configuration in our Spring `MvcInitializer`, as the following example shows:
====
.src/main/java/sample/mvc/MvcInitializer.java
[source,java,indent=0]
----
include::{samples-dir}javaconfig/rest/src/main/java/sample/mvc/MvcInitializer.java[tags=config]
----
====
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` that makes this extremely easy. Simply extend the class with the default constructor as shown below:
Last, we need to ensure that our Servlet Container (that is, Tomcat) uses our `springSessionRepositoryFilter` for every request.
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` that makes doing so easy. To do so, extend the class with the default constructor, as the following example shows:
====
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/rest/src/main/java/sample/Initializer.java[tags=class]
----
====
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
NOTE: The name of our class (`Initializer`) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
// end::config[]
[[rest-sample]]
== rest Sample Application
== `rest` Sample Application
=== Running the rest Sample Application
This section describes how to use the `rest` sample application.
=== Running the `rest` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
NOTE: For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost.
See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
----
$ ./gradlew :spring-session-sample-javaconfig-rest:tomcatRun
----
====
You should now be able to access the application at http://localhost:8080/
=== Exploring the rest Sample Application
=== Exploring the `rest` Sample Application
Try using the application. Use your favorite REST client to request http://localhost:8080/
You can now try to use the application. To do so, use your favorite REST client to request http://localhost:8080/
====
----
$ curl -v http://localhost:8080/
----
====
Observe that we are prompted for basic authentication. Provide the following information for the username and password:
Note that you are prompted for basic authentication. Provide the following information for the username and password:
* **Username** *user*
* **Password** *password*
* *Username* _user-
* *Password* _password_
Then run the following command:
====
----
$ curl -v http://localhost:8080/ -u user:password
----
====
In the output you will notice the following:
In the output, you should notice the following:
====
----
HTTP/1.1 200 OK
...
@@ -159,44 +186,62 @@ X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3
{"username":"user"}
----
====
Specifically, we notice the following things about our response:
Specifically, you should notice the following things about our response:
* The HTTP Status is now a 200
* We have a header with the name of *X-Auth-Token* which contains a new session id
* The current username is displayed
* The HTTP Status is now a 200.
* We have a header a the name of `X-Auth-Token` and that contains a new session ID.
* The current username is displayed.
We can now use the *X-Auth-Token* to make another request without providing the username and password again. For example, the following outputs the username just as before:
We can now use the `X-Auth-Token` to make another request without providing the username and password again. For example, the following command outputs the username, as before:
====
----
$ curl -v http://localhost:8080/ -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
----
====
The only difference is that the session id is not provided in the response headers because we are reusing an existing session.
The only difference is that the session ID is not provided in the response headers because we are reusing an existing session.
If we invalidate the session, then the X-Auth-Token is displayed in the response with an empty value. For example, the following will invalidate our session:
If we invalidate the session, the `X-Auth-Token` is displayed in the response with an empty value. For example, the following command invalidates our session:
====
----
$ curl -v http://localhost:8080/logout -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
----
====
You will see in the output that the X-Auth-Token provides an empty String indicating that the previous session was invalidated.
You can see in the output that the `X-Auth-Token` provides an empty `String` indicating that the previous session was invalidated:
====
----
HTTP/1.1 204 No Content
...
X-Auth-Token:
----
====
=== How does it work?
=== How Does It Work?
Spring Security interacts with the standard `HttpSession` in `SecurityContextPersistenceFilter`.
Instead of using Tomcat's `HttpSession`, Spring Security is now persisting the values in Redis.
Spring Session creates a header named X-Auth-Token in your browser that contains the id of your session.
Spring Session creates a header named `X-Auth-Token` in your browser.
That header contains the ID of your session.
If you like, you can easily see that the session is created in Redis. First create a session using the following:
If you like, you can easily see that the session is created in Redis.
To do so, create a session by using the following command:
====
----
$ curl -v http://localhost:8080/ -u user:password
----
====
In the output you will notice the following:
In the output, you should notice the following:
===
----
HTTP/1.1 200 OK
...
@@ -204,17 +249,32 @@ X-Auth-Token: 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
{"username":"user"}
----
====
Now remove the session using redis-cli. For example, on a Linux based system you can type:
Now you can remove the session by using redis-cli.
For example, on a Linux based system, you can type:
====
----
$ redis-cli keys '*' | xargs redis-cli del
----
====
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
Alternatively, you can also delete the explicit key.
To do so, enter the following into your terminal, being sure to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your `SESSION` cookie:
====
----
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
----
====
We can now use the *X-Auth-Token* to make another request with the session we deleted and observe we are prompted for a authentication. For example, the following returns an HTTP 401:
We can now use the `X-Auth-Token` to make another request with the session we deleted and observe we that are prompted for authentication. For example, the following returns an HTTP 401:
====
----
$ curl -v http://localhost:8080/ -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
----
====

View File

@@ -5,12 +5,13 @@ Rob Winch
This guide describes how to use Spring Session along with Spring Security.
It assumes you have already applied Spring Security to your application.
NOTE: The completed guide can be found in the <<security-sample, security sample application>>.
NOTE: You can find the completed guide in the <<security-sample, security sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
If you are using Maven, ensure to add the following dependencies:
Before you use Spring Session, you must update your dependencies.
If you use Maven, you must add the following dependencies:
====
.pom.xml
[source,xml]
[subs="verbatim,attributes"]
@@ -36,11 +37,13 @@ If you are using Maven, ensure to add the following dependencies:
</dependency>
</dependencies>
----
====
ifeval::["{version-snapshot}" == "true"]
Since We are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a SNAPSHOT version, we need to add the Spring Snapshot Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -54,12 +57,14 @@ Ensure you have the following in your pom.xml:
</repository>
</repositories>
----
====
endif::[]
ifeval::["{version-milestone}" == "true"]
Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a Milestone version, we need to add the Spring Milestone Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -68,107 +73,121 @@ Ensure you have the following in your pom.xml:
<url>https://repo.spring.io/libs-milestone</url>
</repository>
----
====
endif::[]
[[security-spring-configuration]]
== Spring Configuration
After adding the required dependencies, we can create our Spring configuration.
The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
Add the following Spring Configuration:
The Spring configuration is responsible for creating a servlet filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
To do so, add the following Spring Configuration:
====
[source,java]
----
include::{samples-dir}javaconfig/security/src/main/java/sample/Config.java[tags=class]
----
<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
<1> The `@EnableRedisHttpSession` annotation creates a Spring bean with the name of `springSessionRepositoryFilter` that implements `Filter`.
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance Spring Session is backed by Redis.
<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server.
We configure the connection to connect to localhost on the default port (6379)
For more information on configuring Spring Data Redis, refer to the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
For more information on configuring Spring Data Redis, see the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
====
== Servlet Container Initialization
Our <<security-spring-configuration,Spring Configuration>> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`.
Our <<security-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, Spring needs to load our `Config` class.
Since our application is already loading Spring configuration using our `SecurityInitializer` class, we can simply add our Config class to it.
Since our application is already loading Spring configuration by using our `SecurityInitializer` class, we can add our configuration class to it.
The following example shows how to do so:
====
.src/main/java/sample/SecurityInitializer.java
[source,java]
----
include::{samples-dir}javaconfig/security/src/main/java/sample/SecurityInitializer.java[tags=class]
----
====
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
Last, we need to ensure that our Servlet Container (that is, Tomcat) uses our `springSessionRepositoryFilter` for every request.
It is extremely important that Spring Session's `springSessionRepositoryFilter` is invoked before Spring Security's `springSecurityFilterChain`.
This ensures that the `HttpSession` that Spring Security uses is backed by Spring Session.
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` that makes this extremely easy.
You can find an example below:
Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` that makes doing so easy.
The following example shows how to do so:
====
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/security/src/main/java/sample/Initializer.java[tags=class]
----
====
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
By extending `AbstractHttpSessionApplicationInitializer` we ensure that the Spring Bean by the name `springSessionRepositoryFilter` is registered with our Servlet Container for every request before Spring Security's `springSecurityFilterChain` .
By extending `AbstractHttpSessionApplicationInitializer`, we ensure that the Spring bean named `springSessionRepositoryFilter` is registered with our Servlet Container for every request before Spring Security's `springSecurityFilterChain` .
[[security-sample]]
== security Sample Application
== `security` Sample Application
This section describes how to work with the `security` sample application.
=== Running the security Sample Application
=== Running the `security` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
----
$ ./gradlew :spring-session-sample-javaconfig-security:tomcatRun
----
====
NOTE: For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost.
See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
You should now be able to access the application at http://localhost:8080/
=== Exploring the security Sample Application
=== Exploring the `security` Sample Application
Try using the application. Enter the following to log in:
Now you can use the application. Enter the following to log in:
* **Username** _user_
* **Password** _password_
* *Username* _user_
* *Password* _password_
Now click the **Login** button.
Now click the *Login* button.
You should now see a message indicating your are logged in with the user entered previously.
The user's information is stored in Redis rather than Tomcat's `HttpSession` implementation.
=== How does it work?
=== How Does It Work?
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis.
Instead of using Tomcat's `HttpSession`, we persist the values in Redis.
Spring Session replaces the `HttpSession` with an implementation that is backed by Redis.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into Redis.
When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`, it is then persisted into Redis.
When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
When a new `HttpSession` is created, Spring Session creates a cookie named `SESSION` in your browser.
That cookie contains the ID of your session.
You can view the cookies (with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type:
You can remove the session using redis-cli. For example, on a Linux-based system you can type the following command:
====
----
$ redis-cli keys '*' | xargs redis-cli del
----
====
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
Alternatively, you can also delete the explicit key.
Enter the following command into your terminal, being sure to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your `SESSION` cookie:
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated.
Now you can visit the application at http://localhost:8080/ and see that we are no longer authenticated.

View File

@@ -4,12 +4,14 @@ Rob Winch, Vedran Pavić
This guide describes how to use Spring Session to transparently leverage a relational to back a web application's `HttpSession` with XML based configuration.
NOTE: The completed guide can be found in the <<httpsession-jdbc-xml-sample, httpsession-jdbc-xml sample application>>.
NOTE: You can find the completed guide in the <<httpsession-jdbc-xml-sample, httpsession-jdbc-xml sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
If you are using Maven, ensure to add the following dependencies:
Before you use Spring Session, you must update your dependencies.
If you are using Maven, you must add the following dependencies:
====
.pom.xml
[source,xml]
[subs="verbatim,attributes"]
@@ -30,11 +32,13 @@ If you are using Maven, ensure to add the following dependencies:
</dependency>
</dependencies>
----
====
ifeval::["{version-snapshot}" == "true"]
Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a SNAPSHOT version, we need to add the Spring Snapshot Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -48,12 +52,14 @@ Ensure you have the following in your pom.xml:
</repository>
</repositories>
----
====
endif::[]
ifeval::["{version-milestone}" == "true"]
Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a Milestone version, we need to add the Spring Milestone Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -63,6 +69,7 @@ Ensure you have the following in your pom.xml:
</repository>
----
endif::[]
====
// tag::config[]
@@ -70,9 +77,10 @@ endif::[]
== Spring XML Configuration
After adding the required dependencies, we can create our Spring configuration.
The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
Add the following Spring Configuration:
The Spring configuration is responsible for creating a servlet filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
The following listing shows how to add the following Spring Configuration:
====
.src/main/webapp/WEB-INF/spring/session.xml
[source,xml,indent=0]
----
@@ -80,83 +88,94 @@ include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/spring/session.xml[tags=b
----
<1> We use the combination of `<context:annotation-config/>` and `JdbcHttpSessionConfiguration` because Spring Session does not yet provide XML Namespace support (see https://github.com/spring-projects/spring-session/issues/104[gh-104]).
This creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance Spring Session is backed by a relational database.
<2> We create a `dataSource` that connects Spring Session to an embedded instance of H2 database.
We configure the H2 database to create database tables using the SQL script which is included in Spring Session.
This creates a Spring bean with the name of `springSessionRepositoryFilter`.
That bean implements `Filter`.
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance, Spring Session is backed by a relational database.
<2> We create a `dataSource` that connects Spring Session to an embedded instance of an H2 database.
We configure the H2 database to create database tables by using the SQL script that is included in Spring Session.
<3> We create a `transactionManager` that manages transactions for previously configured `dataSource`.
====
For additional information on how to configure data access related concerns, please refer to the https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/data-access.html[Spring Framework Reference Documentation].
For additional information on how to configure data access-related concerns, see the https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/data-access.html[Spring Framework Reference Documentation].
== XML Servlet Container Initialization
Our <<httpsession-xml-spring-configuration,Spring Configuration>> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`.
Our <<httpsession-xml-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, we need to instruct Spring to load our `session.xml` configuration.
We do this with the following configuration:
We do so with the following configuration:
====
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=listeners]
----
====
The https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/core.html#context-create[ContextLoaderListener] reads the contextConfigLocation and picks up our session.xml configuration.
The https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/core.html#context-create[`ContextLoaderListener`] reads the `contextConfigLocation` and picks up our session.xml configuration.
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
Last, we need to ensure that our Servlet Container (that is, Tomcat) uses our `springSessionRepositoryFilter` for every request.
The following snippet performs this last step for us:
====
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
----
====
The https://docs.spring.io/spring-framework/docs/{spring-framework-version}/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`.
For every request that `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` will be invoked.
The https://docs.spring.io/spring-framework/docs/{spring-framework-version}/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[`DelegatingFilterProxy`] looks up a bean named `springSessionRepositoryFilter` and casts it to a `Filter`.
For every request on which `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` is invoked.
// end::config[]
[[httpsession-jdbc-xml-sample]]
== httpsession-jdbc-xml Sample Application
== `httpsession-jdbc-xml` Sample Application
=== Running the httpsession-jdbc-xml Sample Application
This section describes how to work with the `httpsession-jdbc-xml` Sample Application.
=== Running the `httpsession-jdbc-xml` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
====
----
$ ./gradlew :spring-session-sample-xml-jdbc:tomcatRun
----
====
You should now be able to access the application at http://localhost:8080/
=== Exploring the httpsession-jdbc-xml Sample Application
=== Exploring the `httpsession-jdbc-xml` Sample Application
Try using the application. Fill out the form with the following information:
Now you can try using the application. To do so, fill out the form with the following information:
* **Attribute Name:** _username_
* **Attribute Value:** _rob_
* *Attribute Name:* _username_
* *Attribute Value:* _rob_
Now click the **Set Attribute** button. You should now see the values displayed in the table.
Now click the *Set Attribute* button. You should now see the values displayed in the table.
=== How does it work?
=== How Does It Work?
We interact with the standard `HttpSession` in the `SessionServlet` shown below:
We interact with the standard `HttpSession` in the following `SessionServlet`:
====
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}xml/jdbc/src/main/java/sample/SessionServlet.java[tags=class]
----
====
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database.
Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
Instead of using Tomcat's `HttpSession`, we persist the values in the H2 database.
Spring Session creates a cookie named `SESSION` in your browser. That cookie contains the ID of your session.
You can view the cookies (with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
If you like, you can easily remove the session using H2 web console available at: http://localhost:8080/h2-console/ (use `jdbc:h2:mem:testdb` for JDBC URL)
You can remove the session by using H2 web console available at: http://localhost:8080/h2-console/ (use `jdbc:h2:mem:testdb` for JDBC URL)
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
Now you can visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.

View File

@@ -2,14 +2,15 @@
Rob Winch
:toc:
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` with XML based configuration.
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` with XML-based configuration.
NOTE: The completed guide can be found in the <<httpsession-xml-sample, httpsession-xml sample application>>.
NOTE: You can find the completed guide in the <<httpsession-xml-sample, httpsession-xml sample application>>.
== Updating Dependencies
Before you use Spring Session, you must ensure to update your dependencies.
If you are using Maven, ensure to add the following dependencies:
Before you use Spring Session, you must update your dependencies.
If you use Maven, you must add the following dependencies:
====
.pom.xml
[source,xml]
[subs="verbatim,attributes"]
@@ -35,11 +36,13 @@ If you are using Maven, ensure to add the following dependencies:
</dependency>
</dependencies>
----
====
ifeval::["{version-snapshot}" == "true"]
Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a SNAPSHOT version, we need to add the Spring Snapshot Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -53,12 +56,14 @@ Ensure you have the following in your pom.xml:
</repository>
</repositories>
----
====
endif::[]
ifeval::["{version-milestone}" == "true"]
Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository.
Ensure you have the following in your pom.xml:
Since we are using a Milestone version, we need to add the Spring Milestone Maven Repository.
You must have the following in your pom.xml:
====
.pom.xml
[source,xml]
----
@@ -67,6 +72,7 @@ Ensure you have the following in your pom.xml:
<url>https://repo.spring.io/libs-milestone</url>
</repository>
----
====
endif::[]
// tag::config[]
@@ -75,9 +81,10 @@ endif::[]
== Spring XML Configuration
After adding the required dependencies, we can create our Spring configuration.
The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
Add the following Spring Configuration:
The Spring configuration is responsible for creating a servlet filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session.
To do so, add the following Spring Configuration:
====
.src/main/webapp/WEB-INF/spring/session.xml
[source,xml,indent=0]
----
@@ -85,12 +92,13 @@ include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/spring/session.xml[tags=
----
<1> We use the combination of `<context:annotation-config/>` and `RedisHttpSessionConfiguration` because Spring Session does not yet provide XML Namespace support (see https://github.com/spring-projects/spring-session/issues/104[gh-104]).
This creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance Spring Session is backed by Redis.
This creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements `Filter`.
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
In this instance, Spring Session is backed by Redis.
<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server.
We configure the connection to connect to localhost on the default port (6379)
For more information on configuring Spring Data Redis, refer to the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
For more information on configuring Spring Data Redis, see the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
====
== XML Servlet Container Initialization
@@ -98,83 +106,99 @@ Our <<httpsession-xml-spring-configuration,Spring Configuration>> created a Spri
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, we need to instruct Spring to load our `session.xml` configuration.
We do this with the following configuration:
We can do so with the following configuration:
====
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/web.xml[tags=listeners]
----
====
The https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/core.html#context-create[ContextLoaderListener] reads the contextConfigLocation and picks up our session.xml configuration.
The https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/core.html#context-create[`ContextLoaderListener`] reads the contextConfigLocation and picks up our session.xml configuration.
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
Last, we need to ensure that our Servlet Container (that is, Tomcat) uses our `springSessionRepositoryFilter` for every request.
The following snippet performs this last step for us:
====
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
----
====
The https://docs.spring.io/spring-framework/docs/{spring-framework-version}/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`.
For every request that `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` will be invoked.
The https://docs.spring.io/spring-framework/docs/{spring-framework-version}/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[`DelegatingFilterProxy`] looks up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`.
For every request that `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` is invoked.
// end::config[]
[[httpsession-xml-sample]]
== httpsession-xml Sample Application
== `httpsession-xml` Sample Application
=== Running the httpsession-xml Sample Application
This section describes how to work with the `httpsession-xml` sample application.
=== Running the `httpsession-xml` Sample Application
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
NOTE: For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
====
====
----
$ ./gradlew :spring-session-sample-xml-redis:tomcatRun
----
====
You should now be able to access the application at http://localhost:8080/
=== Exploring the httpsession-xml Sample Application
=== Exploring the `httpsession-xml` Sample Application
Try using the application. Fill out the form with the following information:
Now you can try using the application. Fill out the form with the following information:
* **Attribute Name:** _username_
* **Attribute Value:** _rob_
* *Attribute Name:* _username_
* *Attribute Value:* _rob_
Now click the **Set Attribute** button. You should now see the values displayed in the table.
Now click the *Set Attribute* button. You should now see the values displayed in the table.
=== How does it work?
=== How Does It Work?
We interact with the standard `HttpSession` in the `SessionServlet` shown below:
We interact with the standard `HttpSession` in the `SessionServlet` shown in the following listing:
====
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}xml/redis/src/main/java/sample/SessionServlet.java[tags=class]
----
====
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis.
Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
Instead of using Tomcat's `HttpSession`, we persist the values in Redis.
Spring Session creates a cookie named SESSION in your browser.
That cookie contains the ID of your session.
You can view the cookies (with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type:
You can remove the session using redis-cli.
For example, on a Linux based system you can type the following:
====
----
$ redis-cli keys '*' | xargs redis-cli del
----
====
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
Alternatively, you can also delete the explicit key. To do so, enter the following into your terminal, being sure to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
====
----
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
----
====
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
Now you can visit the application at http://localhost:8080/ and see that the attribute we added is no longer displayed.

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,
@@ -24,7 +24,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.session.MapSessionRepository;
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
@@ -54,7 +53,7 @@ public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapte
// tag::rememberme-bean[]
@Bean
RememberMeServices rememberMeServices() {
public SpringSessionRememberMeServices rememberMeServices() {
SpringSessionRememberMeServices rememberMeServices =
new SpringSessionRememberMeServices();
// optionally customize

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* 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
* https://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,
@@ -30,10 +30,11 @@ import org.springframework.session.security.SpringSessionBackedSessionRegistry;
*/
// tag::class[]
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
public class SecurityConfiguration<S extends Session>
extends WebSecurityConfigurerAdapter {
@Autowired
private FindByIndexNameSessionRepository<Session> sessionRepository;
private FindByIndexNameSessionRepository<S> sessionRepository;
@Override
protected void configure(HttpSecurity http) throws Exception {
@@ -47,7 +48,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
}
@Bean
SpringSessionBackedSessionRegistry sessionRegistry() {
public SpringSessionBackedSessionRegistry<S> sessionRegistry() {
return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
}
}

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -4,9 +4,9 @@
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-4.1.xsd">
<context:annotation-config/>

View File

@@ -4,9 +4,9 @@
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-4.1.xsd">
<!-- tag::config[] -->
<bean class="org.springframework.security.web.session.HttpSessionEventPublisher"/>

View File

@@ -3,8 +3,8 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- tag::config[] -->
<security:http>

View File

@@ -2,8 +2,8 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
<!-- tag::config[] -->
<security:http>

View File

@@ -1,10 +1,10 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<!-- Supressions -->
<module name="SuppressionFilter">
<property name="file" value="${configDir}/suppressions.xml"/>
<property name="file" value="${config_loc}/suppressions.xml"/>
</module>
<!-- Root Checks -->

View File

@@ -1,16 +0,0 @@
^\Q/*\E$
^\Q * Copyright 2014-\E20\d\d\Q the original author or authors.\E$
^\Q *\E$
^\Q * Licensed under the Apache License, Version 2.0 (the "License");\E$
^\Q * you may not use this file except in compliance with the License.\E$
^\Q * You may obtain a copy of the License at\E$
^\Q *\E$
^\Q * http://www.apache.org/licenses/LICENSE-2.0\E$
^\Q *\E$
^\Q * Unless required by applicable law or agreed to in writing, software\E$
^\Q * distributed under the License is distributed on an "AS IS" BASIS,\E$
^\Q * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\E$
^\Q * See the License for the specific language governing permissions and\E$
^\Q * limitations under the License.\E$
^\Q */\E$
^.*$

View File

@@ -1,16 +1,17 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<!DOCTYPE suppressions PUBLIC "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<!-- global -->
<suppress files="[\\/]src[\\/]integration-test[\\/]java[\\/]" checks="Javadoc*"/>
<!-- docs -->
<suppress files="[\\/]docs[\\/]" checks="Javadoc*"/>
<suppress files="[\\/]docs[\\/]" checks="AvoidStaticImport"/>
<suppress files="[\\/]docs[\\/]" checks="InnerTypeLast"/>
<!-- samples -->
<suppress files="[\\/]samples[\\/]" checks="Javadoc*"/>
<suppress files="[\\/]samples[\\/].+Application\.java" checks="HideUtilityClassConstructor"/>
<suppress files="SessionRepositoryFilterTests\.java" checks="SpringLambda"/>
</suppressions>

View File

@@ -1,2 +1 @@
springBootVersion=2.1.0.M1
version=2.1.0.M2
version=2.2.0.M1

View File

@@ -1,32 +1,33 @@
dependencyManagement {
imports {
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.6'
mavenBom 'io.projectreactor:reactor-bom:Californium-M2'
mavenBom 'org.springframework:spring-framework-bom:5.1.0.RC2'
mavenBom 'org.springframework.data:spring-data-releasetrain:Lovelace-RC2'
mavenBom 'org.springframework.security:spring-security-bom:5.1.0.RC1'
mavenBom 'org.testcontainers:testcontainers-bom:1.8.3'
mavenBom 'io.projectreactor:reactor-bom:Californium-SR6'
mavenBom 'org.springframework:spring-framework-bom:5.2.0.M1'
mavenBom 'org.springframework.data:spring-data-releasetrain:Moore-M3'
mavenBom 'org.springframework.security:spring-security-bom:5.2.0.M1'
mavenBom 'org.testcontainers:testcontainers-bom:1.11.1'
}
dependencies {
dependencySet(group: 'com.hazelcast', version: '3.10.4') {
dependencySet(group: 'com.hazelcast', version: '3.12') {
entry 'hazelcast'
entry 'hazelcast-client'
}
dependency 'com.h2database:h2:1.4.197'
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.0.0.jre8'
dependency 'com.h2database:h2:1.4.199'
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8'
dependency 'com.zaxxer:HikariCP:3.3.1'
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
dependency 'io.lettuce:lettuce-core:5.1.0.M1'
dependency 'io.lettuce:lettuce-core:5.1.6.RELEASE'
dependency 'javax.annotation:javax.annotation-api:1.3.2'
dependency 'javax.servlet:javax.servlet-api:4.0.1'
dependency 'junit:junit:4.12'
dependency 'mysql:mysql-connector-java:8.0.12'
dependency 'mysql:mysql-connector-java:8.0.15'
dependency 'org.apache.derby:derby:10.14.2.0'
dependency 'org.assertj:assertj-core:3.11.0'
dependency 'org.assertj:assertj-core:3.12.2'
dependency 'org.hsqldb:hsqldb:2.4.1'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.2.6'
dependency 'org.mockito:mockito-core:2.21.0'
dependency 'org.postgresql:postgresql:42.2.4'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.4.1'
dependency 'org.mockito:mockito-core:2.26.0'
dependency 'org.postgresql:postgresql:42.2.5'
}
}

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

18
gradlew vendored
View File

@@ -1,5 +1,21 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# 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.
#
##############################################################################
##
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

18
gradlew.bat vendored
View File

@@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* 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
* https://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,
@@ -46,7 +46,7 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class FindByUsernameTests {
private static final String DOCKER_IMAGE = "redis:4.0.11";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Autowired
private MockMvc mockMvc;

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -0,0 +1 @@
ryuk.container.timeout=120

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -1,4 +1,4 @@
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
<html xmlns:th="https://www.thymeleaf.org" xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect" layout:decorate="~{layout}">
<head>
<title>Secured Content</title>
</head>

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd">
<!DOCTYPE html SYSTEM "https://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
xmlns:th="https://www.thymeleaf.org"
xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect">
<head>
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>
@@ -115,7 +115,7 @@
<div id="footer">
<div class="container">
<p class="muted credit">This product includes GeoLite2 data created by MaxMind, available from <a href="http://www.maxmind.com">http://www.maxmind.com</a>.</p>
<p class="muted credit">This product includes GeoLite2 data created by MaxMind, available from <a href="https://www.maxmind.com">https://www.maxmind.com</a>.</p>
</div>
</div>
</body>

View File

@@ -1,5 +1,5 @@
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
<html xmlns:th="https://www.thymeleaf.org"
xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect"
layout:decorate="~{layout}">
<head>
<title>Log In</title>

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -1,4 +1,4 @@
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
<html xmlns:th="https://www.thymeleaf.org" xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect" layout:decorate="~{layout}">
<head>
<title>Secured Content</title>
</head>

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd">
<!DOCTYPE html SYSTEM "https://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
xmlns:th="https://www.thymeleaf.org"
xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect">
<head>
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* 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
* https://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,
@@ -50,7 +50,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@AutoConfigureMockMvc
public class HttpRedisJsonTest {
private static final String DOCKER_IMAGE = "redis:4.0.11";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Autowired
private MockMvc mockMvc;

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* 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
* https://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,
@@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
public class RedisSerializerTest {
private static final String DOCKER_IMAGE = "redis:4.0.11";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@SpringSessionRedisOperations
private RedisTemplate<Object, Object> sessionRedisTemplate;

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -0,0 +1 @@
ryuk.container.timeout=120

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
<html xmlns:th="https://www.thymeleaf.org" xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect" layout:decorate="~{layout}">
<head>
<title>Home</title>
</head>

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd">
<!DOCTYPE html SYSTEM "https://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
xmlns:th="https://www.thymeleaf.org"
xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect">
<head>
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
<html xmlns:th="https://www.thymeleaf.org" xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect" layout:decorate="~{layout}">
<head>
<title>Login</title>
</head>

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* 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
* https://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,
@@ -45,7 +45,7 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class BootTests {
private static final String DOCKER_IMAGE = "redis:4.0.11";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Autowired
private MockMvc mockMvc;

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -0,0 +1 @@
ryuk.container.timeout=120

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -5,7 +5,7 @@
* 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
* https://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,

View File

@@ -1,4 +1,4 @@
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
<html xmlns:th="https://www.thymeleaf.org" xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect" layout:decorate="~{layout}">
<head>
<title>Secured Content</title>
</head>

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd">
<!DOCTYPE html SYSTEM "https://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
xmlns:th="https://www.thymeleaf.org"
xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect">
<head>
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* 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
* https://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,
@@ -47,7 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class AttributeTests {
private static final String DOCKER_IMAGE = "redis:4.0.11";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@LocalServerPort
private int port;

Some files were not shown because too many files have changed in this diff Show More