Compare commits

..

453 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
Vedran Pavic
0c2f756533 Release 2.1.0.M2 2018-08-21 06:33:12 +02:00
Vedran Pavic
de16c304ea Add support using JDBC repository without transactions
Closes gh-1046
2018-08-21 06:05:52 +02:00
Vedran Pavic
3ce3962ebd Upgrade Spring Security to 5.1.0.RC1
Closes gh-1144
2018-08-20 20:41:38 +02:00
Vedran Pavic
3c4a309a0f Upgrade Spring Data to Lovelace-RC2
Closes gh-1143
2018-08-20 11:51:28 +02:00
Vedran Pavic
38de434158 Add support for @SpringSessionRedisOperations in reactive Redis repository
Closes gh-1164
2018-08-20 07:23:23 +02:00
Vedran Pavic
7ef0faf259 Update integration tests 2018-08-20 06:31:10 +02:00
Vedran Pavic
f65cee0a7b Upgrade dependencies 2018-08-20 06:31:10 +02:00
Vedran Pavic
a2cd1e37fa Add support for configuring custom RedisSerializer in reactive config
Closes gh-1149
2018-08-20 06:31:09 +02:00
Vedran Pavic
b768042506 Upgrade Spring Framework to 5.1.0.RC2
Closes gh-1141
2018-08-17 12:21:48 +02:00
Vedran Pavic
3140bd06b2 Add FindByIndexNameSessionRepository#findByPrincipalName default method
Closes gh-1158
2018-08-17 08:04:09 +02:00
Vedran Pavic
172c18d666 Upgrade Reactor to Californium-M2
Closes gh-1142
2018-08-16 07:13:59 +02:00
Vedran Pavic
7fdf2876b2 Polish 2018-08-13 07:44:47 +02:00
Vedran Pavic
87c2e53b5a Insert new attributes conditionally in JDBC repo
At present, the insert of new attributes in JdbcOperationsSessionRepository is done unconditionally. This can cause data integrity violation errors with concurrent requests, where one request attempts to add new session attribute while the other, concurrent request, deletes the session.

This commit addresses the described scenario by executing insert of new attributes conditionally on presence of parent record.

Closes gh-1031
2018-08-13 06:28:42 +02:00
Vedran Pavic
268ba663e5 Remove SpringSessionWebSessionStore#storeSession
Closes gh-1150
2018-08-09 16:32:14 +02:00
Vedran Pavic
3f4873f0eb Simplify tests related to SameSite cookie directive support
Closes gh-1147
2018-08-03 23:20:55 +02:00
Vedran Pavic
644239ee14 Start building against Spring Framework 5.1.0 snapshots
See gh-1141
2018-08-03 23:20:52 +02:00
Johnny Lim
97e52de41b Make MapSession.originalId final
Closes gh-1146
2018-08-02 18:46:59 +02:00
Vedran Pavic
f4bbc18f94 Fix Jenkinsfile 2018-08-01 02:00:48 +02:00
Vedran Pavic
dfe216b482 Update Jenkinsfile
- set check stage timeout to 30 minutes
 - set build discared to keep last 10 builds
 - handle deploy stage errors
 - general formatting improvements
2018-08-01 01:01:32 +02:00
Vedran Pavic
a976c9dd6d Upgrade samples to Spring Boot 2.1.0.M1
Closes gh-1139
2018-07-31 22:22:50 +02:00
Vedran Pavic
deb2863507 Next development version 2018-07-30 02:49:33 +02:00
Vedran Pavic
7bdb3f6ded Release 2.1.0.M1 2018-07-30 02:36:01 +02:00
Vedran Pavic
7d3472f55d Remove Spring IO check from build 2018-07-30 02:31:00 +02:00
Vedran Pavic
00465a6f00 Add support for SameSite cookie directive
Closes gh-1005
2018-07-30 02:13:57 +02:00
Vedran Pavic
ad35d7ca30 Add support for HttpSessionBindingListener
Closes gh-1018
2018-07-29 08:09:00 +02:00
Vedran Pavic
18e9ab4c0f Polish 2018-07-27 13:14:04 +02:00
Vedran Pavic
1c9a6d3e5d Upgrade Spring Security to 5.1.0.M2
Closes gh-1125
2018-07-27 13:13:19 +02:00
Vedran Pavic
d2936ed0b4 Upgrade dependencies 2018-07-27 11:10:14 +02:00
Vedran Pavic
cdf6089ccd Upgrade Spring Data to Lovelace-RC1
Closes gh-1126
2018-07-26 23:14:16 +02:00
Vedran Pavic
1ca8a6476a Upgrade Spring Framework to 5.1.0.RC1
Closes gh-1124
2018-07-26 23:13:31 +02:00
Vedran Pavic
cf926045dc Upgrade Reactor to Californium-M1
Closes gh-1127
2018-07-25 22:05:19 +02:00
Vedran Pavic
7123df8656 Remove MapSession#setOriginalId
Closes gh-1100
2018-07-25 22:03:19 +02:00
Rob Winch
096a5683cb Spring Session Core 2.1.0.BUILD-SNAPSHOT 2018-07-25 10:32:29 -07:00
Vedran Pavic
db31527c8c Add logging for errors decoding Base64 cookies
Closes gh-1117
2018-07-24 23:37:52 +02:00
Vedran Pavic
3d2a742328 Use Spring Java Format Checkstyle
Closes gh-1113
2018-07-23 15:16:35 +02:00
Vedran Pavic
7ac6e458e0 Update integration tests 2018-07-23 12:15:14 +02:00
Vedran Pavic
9adf0a6e0c Upgrade spring-build-conventions to 0.0.17.RELEASE 2018-07-18 09:38:02 +02:00
Vedran Pavic
58219fa016 Upgrade Gradle to 4.9 2018-07-18 08:15:38 +02:00
Vedran Pavic
83cbff5ce2 Improve support for Hazelcast client-server topology
This commit improves support for use of Spring Session with Hazelcast's client-server topology by ensuring SessionUpdateEntryProcessor is easier to serialize to the cluster. This is done by refactoring SessionUpdateEntryProcessor from static inner class of HazelcastSessionRepository to a dedicated class, therefore minimizing the dependencies to other Spring Session components.

Closes gh-1101
2018-07-17 21:42:33 +02:00
Vedran Pavic
936fc853df Ensure Session#getAttributeNames implementations return a copy
Currently, Session#getAttributeNames implementations, by delegating to MapSession, all return a session attribute map's key set. This causes ConcurrentModificationException when an attempt to modify session attributes is made while iterating over the returned attribute names.

Closes gh-1120
2018-07-17 15:05:03 +02:00
Vedran Pavic
dba475c48f Invalidate session before clearing session store
Closes gh-1114
2018-07-13 10:50:49 +02:00
Vedran Pavic
9956e91b93 Upgrade samples to Spring Boot 2.0.3.RELEASE
Closes gh-1107
2018-07-13 10:50:49 +02:00
Dave Syer
c902981eba Fix garbled syntax relating to dropped APIs 2018-07-11 08:07:58 -05:00
Vedran Pavic
2e26c6e9d3 Upgrade Gradle to 4.8.1 2018-06-21 22:53:20 +02:00
Vedran Pavic
b9cd3865c5 Next development version 2018-06-13 23:13:05 +02:00
Vedran Pavic
1f7232f12e Release 2.0.4.RELEASE 2018-06-13 23:06:09 +02:00
Vedran Pavic
03f0a571b6 Upgrade Spring Data to Kay-SR8
See gh-1094
2018-06-13 22:44:12 +02:00
Vedran Pavic
63a215f73b Disable network join in Hazelcast integration tests 2018-06-13 17:01:57 +02:00
Vedran Pavic
8dac35cf73 Fix session event handling in HazelcastSessionRepository
Previously, invoking HttpServletRequest#changeSessionId on session backed by HazelcastSessionRepository generated generated invalid session destroyed and session created events. This was due to use of IMap#remove and IMap#set when handling the change session id.

This commit improves change session id handling to prevent publishing invalid events by using IMap#delete instead of IMap#remove and keeping track of originally assigned session id.

Closes gh-1077
2018-06-13 16:12:28 +02:00
Vedran Pavic
19b8583d65 Adapt to Spring Framework deprecations
See gh-1092
2018-06-13 05:59:50 +02:00
Vedran Pavic
6de0f44241 Upgrade dependencies 2018-06-13 05:41:23 +02:00
Vedran Pavic
60d6120b9c Upgrade Spring Security to 5.0.6.RELEASE
Closes gh-1095
2018-06-13 05:23:56 +02:00
Vedran Pavic
3bc899e695 Upgrade Spring Framework to 5.0.7.RELEASE
Closes gh-1092
2018-06-12 17:41:16 +02:00
Vedran Pavic
c2fe999d6c Update reference manual to mention BOM module
Closes gh-1099
2018-06-12 12:02:48 +02:00
Vedran Pavic
d214971e72 Upgrade Reactor to Bismuth-SR10
Closes gh-1093
2018-06-11 15:21:55 +02:00
Vedran Pavic
f4704293a1 Update integration tests 2018-06-08 16:48:31 +02:00
Vedran Pavic
a8c4f65903 Upgrade spring-build-conventions to 0.0.16.RELEASE 2018-06-05 21:35:48 +02:00
Vedran Pavic
4a52de0c18 Upgrade Gradle to 4.8 2018-06-05 21:34:19 +02:00
Vedran Pavic
63f105082a Optimize Redis integration tests
This commit ensures that Redis Testcontainers used for integration testing are managed by Spring to ensure proper ordering on shutdown.

Previously, Redis Testcontainer was closed before LettuceConnectionFactory which caused pending commands to hang and added a lot of wait to project build.

Closes gh-1086
2018-06-01 11:50:01 +02:00
Vedran Pavic
f55b793185 Remove Servlet API version check from DefaultCookieSerializer
Closes gh-1079
2018-05-31 10:42:44 +02:00
Vedran Pavic
6d027900ee Fix caching of requested session in SessionRepositoryFilter
Closes gh-1076
2018-05-15 10:03:41 +02:00
Vedran Pavic
42818a1b90 Improve update handling in HazelcastSessionRepository
This commit improves HazelcastSessionRepository.SessionUpdateEntryProcessor to avoid NPE in scenario where save operation was invoked for session that was already deleted.

See gh-1076
2018-05-15 08:16:20 +02:00
Vedran Pavic
b6348736ac Polish contribution
Closes gh-1070
2018-05-14 10:38:27 +02:00
Craig Andrews
60581c6427 Fix delta handling in JdbcOperationsSessionRepository
See gh-1070
2018-05-13 21:05:34 +02:00
Craig Andrews
836ea12e93 Upgrade samples to Spring Boot 2.0.2.RELEASE 2018-05-11 09:34:46 -05:00
Rob Winch
670148f182 Next Development Version 2018-05-08 14:45:39 -05:00
Rob Winch
a39295c02b Release 2.0.3 2018-05-08 13:57:03 -05:00
Vedran Pavic
02cd5a6301 Upgrade test dependencies 2018-05-08 19:20:48 +02:00
Vedran Pavic
5824566621 Upgrade Spring Security to 5.0.5.RELEASE
Closes gh-1060
2018-05-08 18:43:03 +02:00
Vedran Pavic
b2711600e2 Polish contribution
Closes gh-1014
2018-05-08 17:35:49 +02:00
Ivan Sopov
06eb768721 Remove redundant index in JDBC schema scripts
See gh-1014
2018-05-08 17:33:16 +02:00
Vedran Pavic
fb05fa70c7 Upgrade Hazelcast to 3.9.4
Closes gh-1067
2018-05-08 17:29:28 +02:00
Vedran Pavic
1e93fe87db Upgrade test dependencies 2018-05-08 17:14:07 +02:00
Vedran Pavic
e67f84c6b6 Upgrade Spring Data to Kay-SR7
See gh-1059
2018-05-08 16:27:17 +02:00
Vedran Pavic
dfb2f2f334 Upgrade Reactor to Bismuth-SR9
See gh-1057
2018-05-08 16:26:27 +02:00
Vedran Pavic
c8e9630fdd Upgrade Spring Framework to 5.0.6.RELEASE
See gh-1058
2018-05-08 16:25:34 +02:00
Vedran Pavic
751375338c Optimize session resolution in SessionRepositoryFilter
This commit optimizes SessionRepositoryFilter to avoid multiple retrievals of session from SessionRepository.

Closes gh-1048
2018-05-04 21:26:35 +02:00
Vedran Pavic
538712d162 Fix compilation warnings 2018-05-04 18:05:39 +02:00
Vedran Pavic
941fdb46f2 Replace use of Test.expected with AssertJ
See gh-1032
2018-05-04 18:05:38 +02:00
Vedran Pavic
bb1c099094 Optimize batch operations in JdbcOperationsSessionRepository
This commit optimizes session attribute saving by ensuring batch updates are used whenever possible. To make this possible, delta now tracks operations for each attribute change in order to be able to deduce SQL operation.

Additionally, if there is only a single attribute change, regular update is executed rather than batch operation.

Closes gh-1051
2018-05-04 16:33:47 +02:00
Vedran Pavic
1d1253e643 Rename expiration key on changeSessionId in RedisOperationsSessionRepository
This commit ensures existing expiration key is renamed on changeSessionId operation in RedisOperationsSessionRepository. Previously, this key wasn't renamed which caused invalid invocations of SessionDestroyedEvent handling when key expired.

Closes gh-1029
2018-04-20 23:08:50 +02:00
Vedran Pavic
0e7e2eaf5c Upgrade samples to Spring Boot 2.0.1.RELEASE
Closes gh-1061
2018-04-20 15:58:19 +02:00
Vedran Pavic
e601e03e1e Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2018-04-20 15:56:30 +02:00
Vedran Pavic
2c81e50b5e Upgrade Spring Security to 5.0.4.RELEASE
Closes gh-1060
2018-04-20 15:18:30 +02:00
Vedran Pavic
ac5ff996f4 Upgrade Spring Data to Kay-SR6
Closes gh-1059
2018-04-20 15:17:58 +02:00
Vedran Pavic
44130cba80 Upgrade Spring Framework to 5.0.5.RELEASE
Closes gh-1058
2018-04-20 15:17:18 +02:00
Vedran Pavic
2cd8063c7c Upgrade Reactor to Bismuth-SR8
Closes gh-1057
2018-04-20 15:16:41 +02:00
Vedran Pavic
f42a6c7d1c Upgrade Gradle to 4.7 2018-04-20 14:10:54 +02:00
Vedran Pavic
6c2f6c26cc Update integration tests
- upgrade TestContainers to 1.7.1
- update Docker images
- improve MariaDB/MySQL tests to use UTF-8

Closes gh-1034
2018-04-20 14:10:52 +02:00
Vedran Pavic
91b4efc5bd Fix attribute mapping in ReactiveRedisOperationsSessionRepository
This commit ensures that attributes with null values are correctly mapped to session on retrieval from Redis.

Closes gh-1035
2018-04-19 15:31:08 +02:00
Vedran Pavic
6f8359ba16 Fix lastAccessedTime handling in SpringSessionWebSessionStore
This commit ensures lastAccessedTime is updated when session is retrieved, as per WebSessionStore API.

Closes gh-1039
2018-04-19 12:11:16 +02:00
Vedran Pavic
62bfeb3f05 Fix ReactiveRedisOperationsSessionRepository tests 2018-04-19 11:08:45 +02:00
Vedran Pavic
2395582fe6 Optimize session retrieval in JdbcOperationsSessionRepository
Previously, SessionResultSetExtractor used JdbcSession.setAttribute which had a side effect of freshly loaded session potentially having a non-empty delta and/or changed flag set. This commit optimizes session retrieval to invoke setAttribute directly on the delegate, therefore preventing unnecessary modifications of delta and change flags.

Closes gh-1042
2018-04-16 08:58:16 +02:00
Vedran Pavic
5173026aa8 Improve RedisOperationsSessionRepository tests 2018-04-16 08:52:43 +02:00
Vedran Pavic
d97ad2ca3e Polish 2018-03-31 08:32:18 +02:00
Vedran Pavic
a780ee0264 Replace use of ExpectedException rule with AssertJ
Closes gh-1032
2018-03-31 08:32:16 +02:00
Vedran Pavic
d8e7a2aa9f Add support for EditorConfig 2018-03-26 19:06:35 +02:00
Rob Winch
45b18dec84 Add CVE Reporting to Issue Template 2018-03-20 22:43:50 -05:00
Rob Winch
ec5406fb01 Add CVE Reporting in PR Template 2018-03-20 22:43:27 -05:00
Vedran Pavic
3c2f0fd485 Fix broken links in Spring Boot samples guides
Closes gh-1023
2018-03-20 10:57:03 +01:00
Vedran Pavic
cdfa557442 Update guides for Spring Boot based samples
Closes gh-1025
2018-03-20 10:44:51 +01:00
Vedran Pavic
edc8a7efff Upgrade Spring Boot to 2.0.0.RELEASE
Closes gh-1007
2018-03-09 07:23:38 +01:00
Vedran Pavic
a7a30dad30 Polish contribution
Closes gh-1009
2018-03-09 07:23:38 +01:00
Josh Cummings
be1d3d30a8 Upgrade Gradle to 4.6
See gh-1009
2018-03-09 07:23:28 +01:00
Vedran Pavic
010aa5f013 Next development version 2018-02-20 14:28:45 +01:00
Vedran Pavic
bfcb4afef7 Release 2.0.2.RELEASE 2018-02-20 14:24:54 +01:00
Vedran Pavic
72a902009e Upgrade spring-build-conventions to 0.0.13.RELEASE 2018-02-20 07:34:06 +01:00
Vedran Pavic
1e799f211f Upgrade Spring Security to 5.0.2.RELEASE
Closes gh-998
2018-02-20 07:32:35 +01:00
Vedran Pavic
90599b9bd3 Upgrade Spring Data to Kay-SR4
Closes gh-997
2018-02-19 22:29:17 +01:00
Vedran Pavic
8d7136072a Upgrade Spring Framework to 5.0.4.RELEASE
Closes gh-996
2018-02-19 13:05:58 +01:00
Vedran Pavic
4f0f3806a2 Update integration tests
This commit updates TestContainers dependency and versions of Docker images used in integration tests.
2018-02-19 09:14:56 +01:00
Vedran Pavic
a18037759c Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2018-02-19 09:06:26 +01:00
Vedran Pavic
eb479af1d4 Upgrade Reactor to Bismuth-SR6
Closes gh-999
2018-02-16 19:56:49 +01:00
Vedran Pavic
d0b472e8e2 Ignore SQL Server integration tests 2018-02-12 20:22:39 +01:00
Vedran Pavic
17ee9d51f2 Update integration tests
This commit updates TestContainers dependency and versions of Docker images used in integration tests.
2018-02-12 19:07:59 +01:00
Vedran Pavic
003996a1b3 Upgrade Gradle to 4.5.1 2018-02-06 15:30:09 +01:00
Vedran Pavic
13c0e325b4 Adapt to Spring WebSocket configuration deprecations
Closes gh-994
2018-02-06 15:30:09 +01:00
Vedran Pavic
7acdeffe22 Remove outdated sample docs
Closes gh-989
2018-02-06 15:30:09 +01:00
Vedran Pavic
de03b20619 Upgrade Spring Boot to 2.0.0.RC1
Closes gh-988
2018-02-06 15:30:02 +01:00
Vedran Pavic
becee53dbf Restore CookieSerializer.CookieValue constructor visibility
Closes gh-978
2018-02-05 19:11:08 +01:00
Vedran Pavic
4eb64e8140 Next development version 2018-01-25 18:52:21 +01:00
Vedran Pavic
e520ea237d Release 2.0.1.RELEASE 2018-01-25 18:46:29 +01:00
Vedran Pavic
175e05dcda Update integration tests
This commit updates TestContainers dependency and versions of Docker images used in integration tests.
2018-01-25 16:02:01 +01:00
Vedran Pavic
bb427ff1af Upgrade dependencies 2018-01-25 15:57:19 +01:00
Vedran Pavic
0a65b82373 Upgrade Spring Security to 5.0.1.RELEASE
Closes gh-974
2018-01-25 15:13:00 +01:00
Vedran Pavic
e25c64efae Upgrade Spring Data to Kay-SR3
Closes gh-975
2018-01-25 15:12:04 +01:00
Vedran Pavic
43fcba65c4 Ignore SQL Server integration tests 2018-01-25 15:10:59 +01:00
Vedran Pavic
1cc2c83f36 Polish 2018-01-25 15:10:53 +01:00
Vedran Pavic
0941358807 Upgrade Spring Framework to 5.0.3.RELEASE
Closes gh-973
2018-01-23 10:52:39 +01:00
Vedran Pavic
7d3698515e Upgrade Reactor to Bismuth-SR5
Closes gh-976
2018-01-23 07:32:38 +01:00
Vedran Pavic
d382603445 Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2018-01-23 07:31:32 +01:00
Vedran Pavic
22e3b5ce38 Update integration tests
This commit updates TestContainers dependency and versions of Docker images used in integration tests.
2018-01-22 08:17:52 +01:00
Vedran Pavic
ebd4b349d2 Fix run commands in samples documentation
Closes gh-969
2018-01-18 22:27:09 +01:00
Vedran Pavic
ffa1bca898 Update Redis configuration to use bean classloader
Spring Session 2.0 made changes to Redis configuration facilities so that the `RedisTemplate` used by `RedisOperationsSessionRepository` isn't exposed as a bean anymore. This has a consequence that bean `ClassLoader` isn't applied automatically which causes issues in Spring Boot applications that use DevTools.

This commit restores the previous behavior by updating Redis configuration classes to implement `BeanClassLoaderAware` callback and apply the application `ClassLoader` to `RedisTemplate`. The analogous change was made to reactive Redis configuration.

Closes gh-968
2018-01-18 22:27:02 +01:00
Rob Winch
d0ee9fd16a Use deployArtifacts 2018-01-09 15:13:37 -06:00
Rob Winch
7a631fe414 Next development version 2018-01-09 14:40:10 -06:00
Rob Winch
d217077dec Release 2.0.0.RELEASE 2018-01-09 14:39:16 -06:00
Vedran Pavic
a9b3ce034b Update readme 2018-01-09 20:31:29 +01:00
Vedran Pavic
1ba434a357 Document ReactiveMapSessionRepository map requirements
Closes gh-842
2018-01-09 20:19:22 +01:00
Vedran Pavic
45807998f6 Update documentation for 2.0
Closes gh-199
Closes gh-826
Closes gh-878
Closes gh-893
2018-01-09 13:04:59 -06:00
Vedran Pavic
2f49a8ac25 Ignore SQL Server integration tests
This commit temporarily disables SQL Server integration tests due to frequent container startup failures on Jenkins.

See gh-959
2018-01-09 14:21:48 +01:00
Vedran Pavic
e364511c7e Polish contribution
Closes gh-965
2018-01-08 17:38:29 +01:00
Johnny Lim
79ccbe7066 Polish
See gh-965
2018-01-08 17:38:06 +01:00
Vedran Pavic
1edce117aa Fix Redis change session id handling
This commit updates logic around changing session id in `RedisOperationsSessionRepository` to properly handle updates for new sessions i.e. ones that haven't been saved yet.

Previously, the logic skipped both Redis rename operation and replacement of session id within the current session holder object, which led to no such key errors on subsequent save operation which still observed the session id as changed.

Closes gh-962
2018-01-05 12:52:12 +01:00
Vedran Pavic
c0f4c7f381 Fix reactive Redis change session id handling
This commit updates logic around changing session id in `ReactiveRedisOperationsSessionRepository` to properly handle updates for new sessions i.e. ones that haven't been saved yet.

Previously, the logic skipped both Redis rename operation and replacement of session id within the current session holder object, which led to no such key errors on subsequent save operation which still observed the session id as changed.

Closes gh-954
2018-01-05 12:22:28 +01:00
Vedran Pavic
7fa07b2973 Upgrade Gradle to 4.4.1 2018-01-02 22:37:09 +01:00
Vedran Pavic
3252b38c87 Add Microsoft SQL Server integration tests
Closes gh-959
2018-01-02 22:37:09 +01:00
Vedran Pavic
c4daeff3d8 Update integration tests
This commit updates TestContainers dependency and versions of Docker images used in integration tests.
2018-01-02 21:42:22 +01:00
Vedran Pavic
2fccca1158 Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2018-01-02 21:12:55 +01:00
Vedran Pavic
81798c36f6 Upgrade Gradle to 4.4 2017-12-11 23:58:33 +01:00
Vedran Pavic
27283e29d5 Optimize HazelcastSessionRepository.SessionUpdateEntryProcessor
Closes gh-947
2017-12-01 23:20:19 +01:00
Vedran Pavic
77bb9dfdb1 Upgrade Spring Boot to 2.0.0.M7
Closes gh-930
2017-11-30 12:45:00 +01:00
Rob Winch
c874592323 Next Development Version 2.0.0.BUILD-SNAPSHOT 2017-11-27 21:54:05 -06:00
Rob Winch
676f0e474e Release 2.0.0.RC2 2017-11-27 21:53:36 -06:00
Rob Winch
e5ec612771 Update to Spring Security 5.0.0.RELEASE
Fixes gh-926
2017-11-27 21:53:00 -06:00
Vedran Pavic
280d5c5a77 Refactor JDBC configuration
Closes gh-942
2017-11-27 22:21:40 +01:00
Vedran Pavic
6a370b1ef8 Refactor Redis configuration
Closes gh-941
2017-11-27 22:21:40 +01:00
Vedran Pavic
41de1b087a Refactor Hazelcast configuration
Closes gh-938
2017-11-27 22:21:40 +01:00
Vedran Pavic
6188fe68b7 Improve session event handling
This commit removes constructor that takes session id instead of session object for the entire `AbstractSessionEvent` hierarchy.

The ability to create `AbstractSessionEvent` instances with no underlying session object leads to NPE when interacting with `HttpSession` obtained from `HttpSessionEvent`.

See gh-499
Closes gh-939
2017-11-27 22:21:40 +01:00
Rob Winch
ed328ff4b1 spring-build-conventions:0.0.8.RELEASE 2017-11-27 14:35:15 -06:00
Vedran Pavic
97ad0311e2 Upgrade Spring Data to Kay-SR2
Closes gh-932
2017-11-27 20:07:03 +01:00
Vedran Pavic
702bc37a99 Upgrade Spring Framework to 5.0.2.RELEASE
Closes gh-925
2017-11-27 12:56:09 +01:00
Vedran Pavic
17e56dda18 Polish configuration classes 2017-11-26 12:21:32 +01:00
Vedran Pavic
f5912da089 Optimize HazelcastSessionRepository write operations
This commit introduces several optimizations to write operations in `HazelcastSessionRepository`.

 - when storing a new session, `IMap#set` is now used instead of `IMap#put`
 - when updating an existing session, `IMap#executeOnKey` and a dedicated `EntryProcessor` are used

To make these two changes possible, internal `HazelcastSession` now adds a flag to determine which of the two mentioned write scenarios to use, and also tracks a delta of session attributes in order to optimize updates.

Closes gh-850
2017-11-24 21:06:05 +01:00
Vedran Pavic
bff8ce3c03 Polish samples 2017-11-24 08:21:14 +01:00
Vedran Pavic
a3803e9e1f Update integration tests
This commit updates TestContainers dependency and versions of Docker images used in integration tests.
2017-11-23 13:41:48 +01:00
Vedran Pavic
3fcdc9ebce Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2017-11-23 13:15:47 +01:00
Vedran Pavic
36d157a658 Polish default Redis namespace handling
See gh-919
2017-11-20 09:12:53 +01:00
Vedran Pavic
f28ab07b9a Migrate SpringJUnit4ClassRunner -> SpringRunner 2017-11-20 08:08:00 +01:00
Vedran Pavic
42a6001aae Upgrade Reactor to Bismuth-SR4
Closes gh-929
2017-11-16 20:01:04 +01:00
Vedran Pavic
fc4d2238bc Rename MapReactiveSessionRepository to ReactiveMapSessionRepository
Closes gh-928
2017-11-14 07:26:13 +01:00
Vedran Pavic
36d349f328 Polish contribution
Closes gh-919
2017-11-13 20:59:39 +01:00
Luís Duarte
5f23a41674 Make Redis namespace fully configurable
See gh-919
2017-11-10 22:23:25 +01:00
Vedran Pavic
4c9fbd5b6b Migrate WebFlux sample to Boot
Closes gh-923
2017-11-10 22:11:54 +01:00
Vedran Pavic
f2ba773ec2 Upgrade Spring Boot to 2.0.0.M6
Closes gh-916
2017-11-06 13:01:22 +01:00
Vedran Pavic
647dd7c7bb Add license file 2017-11-02 19:27:25 +01:00
Rob Winch
555223755d Next Development Version 2017-10-30 18:22:30 -05:00
Rob Winch
2e65d89ecc Release 2.0.0.RC1 2017-10-30 18:20:38 -05:00
Rob Winch
f3f18432ee Update to Spring Security 5.0.0.RC1
Fixes gh-904
2017-10-30 18:17:39 -05:00
Vedran Pavic
03f6611e04 Update integration tests
This commit updates TestContainers dependency and versions of Docker images used in integration tests.
2017-10-30 09:05:36 +01:00
Vedran Pavic
fff1d83097 Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2017-10-30 09:01:58 +01:00
Vedran Pavic
91d4a5bfca Add HeaderHttpSessionIdResolver factory methods for commonly used headers
Closes gh-706
2017-10-30 08:07:07 +01:00
Vedran Pavic
34f29cf36c Improve Hazelcast configuration
This commit improves Hazelcast configuration by introducing `@SpringSessionHazelcastInstance` qualifier for explicitly declaring a `HazelcastInstance` to be used by Spring Session. This is in particular useful in scenarios with multiple `HazelcastInstance` beans present in the application context.

 Closes gh-912
2017-10-30 08:03:02 +01:00
Vedran Pavic
7e26897ec2 Add support for configuring Redis session cleanup cron 2017-10-30 01:33:36 -05:00
Vedran Pavic
9ea1fb9af1 Upgrade Spring Data to Kay-SR1
Closes gh-903
2017-10-27 18:31:20 +02:00
Vedran Pavic
2c664d1d9e Move JDBC qualifier annotations to shared package
Closes gh-909
2017-10-27 18:29:49 +02:00
Vedran Pavic
97698fd590 Add support for configuring JDBC session cleanup cron 2017-10-27 14:55:28 +02:00
Vedran Pavic
fe3f40c6f4 Harmonize Redis configurations
This commit improves reactive Redis configuration by adding support for connection factory qualifier and Redis operations resolver annotations.
2017-10-27 13:54:25 +02:00
Vedran Pavic
f8583bb02f Add missing @Override 2017-10-27 09:59:55 +02:00
Vedran Pavic
5df555cd53 Polish 2017-10-27 09:59:51 +02:00
Vedran Pavic
6f05c84aa7 Rename HttpSessionStrategy to HttpSessionIdResolver
This commit harmonizes `HttpSessionStrategy` with Spring Framework's `WebSessionIdResolver` by renaming it to `WebSessionIdResolver`.
2017-10-26 07:29:56 -05:00
Vedran Pavic
cd394bbe10 Align HttpSessionStrategy with WebSessionIdResolver
This commit simplifies `HttpSessionStrategy` API by aligning it with Spring Framework's `WebSessionIdResolver`. As a part of this, support for managing multiple users' sessions has been removed.

Closes gh-275
Closes gh-362
2017-10-26 07:29:56 -05:00
Vedran Pavic
2ecb2e60c0 Improve Redis configuration
This commit improves Redis configuration by introducing `@SpringSessionRedisConnectionFactory` qualifier for explicitly declaring a `RedisConnectionFactory` to be used by Spring Session. This is in particular useful in scenarios with multiple `RedisConnectionFactory` beans present in the application context.

Redis configuration is simplified and no longer registers a Spring Session specific `RedisOperations<Object,Object>` bean with the application context.

Users are however able to obtain `RedisOperations<Object,Object>` instance used by Spring Session using newly introduced `@SpringSessionRedisOperations` annotation.
2017-10-25 07:36:44 -05:00
Vedran Pavic
d04a95ebfb Upgrade Spring Framework to 5.0.1.RELEASE
Closes gh-902
2017-10-24 19:25:07 +02:00
Vedran Pavic
858b52235e Upgrade Reactor to Bismuth-SR3
Closes gh-905
2017-10-24 19:24:29 +02:00
Vedran Pavic
00ede81665 Harmonize naming of reactive components
Closes gh-897
2017-10-24 07:36:25 +02:00
Rob Winch
6cfa975b29 Move Redis Reactive Configuration
Renaming the package to better align with WebSession pacakge structure

Fixes gh-901
2017-10-22 22:37:21 -05:00
Rob Winch
8b9d421ad6 Tangles in RedisOperationsSessionRepository
Issue: gh-900
2017-10-22 22:33:36 -05:00
Rob Winch
df7ab9d99e Package tangles for Reactive Configuration
Fixes gh-900
2017-10-22 22:33:29 -05:00
Vedran Pavic
7d61c5496a Fix deprecation warnings 2017-10-20 21:18:31 +02:00
Vedran Pavic
3492bc01d2 Upgrade Spring Boot to 2.0.0.M5
Closes gh-892
2017-10-12 11:35:46 +02:00
Vedran Pavic
e08ac357dd Upgrade spring-build-conventions to 0.0.5.RELEASE 2017-10-10 22:06:01 +02:00
Rob Winch
1c29c7f14f Update to 5.0.0.BUILD-SNAPSHOT 2017-10-09 17:10:11 -05:00
Rob Winch
33fbaa03a8 Release 2.0.0.M5 2017-10-09 16:54:31 -05:00
Rob Winch
88b26f2cfe Update to Spring Security 5.0.0.M5
Fixes gh-891
2017-10-09 16:53:41 -05:00
Vedran Pavic
3f670050ef Update integration tests
This commit updates versions of RDBMS and Redis Docker images used in
integration tests.

Closes gh-894
2017-10-09 08:09:52 +02:00
Vedran Pavic
e3b61d25bb Improve JDBC configuration
This commit improves JDBC configuration by introducing `@SpringSessionDataSource` qualifier for explicitly declaring a `DataSource` to be used by Spring Session. This is in particular useful in scenarios with multiple `DataSource` beans present in the application context.

As a consequence, JDBC configuration is simplified and no longer registers a Spring Session specific `JdbcTemplate` bean.

Closes gh-863
2017-10-06 19:12:55 +02:00
Vedran Pavic
19b8effa41 Add Redis implementation of ReactorSessionRepository
Closes gh-816
2017-10-06 18:45:42 +02:00
Vedran Pavic
9f5f7540d2 Fix Users sample app navbar
Closes gh-885
2017-10-02 22:31:55 +02:00
Vedran Pavic
eb8c22939c Upgrade Gradle to 4.2.1 2017-10-02 21:20:14 +02:00
Vedran Pavic
45cfa1e9a4 Upgrade spring-build-conventions to 0.0.4.RELEASE 2017-10-02 20:53:06 +02:00
Vedran Pavic
99221e0948 Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2017-10-02 19:01:47 +02:00
Vedran Pavic
41cf2ef152 Update documentation to reflect preference for Lettuce
See gh-886
2017-10-02 19:00:23 +02:00
Vedran Pavic
c51bce4777 Use Lettuce driver for integration tests
Closes gh-886
2017-09-28 16:17:55 +02:00
Vedran Pavic
b6f1184c4c Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2017-09-28 15:51:32 +02:00
Vedran Pavic
c69a8b8762 Improve JDBC data store schema scripts
Closes gh-884
2017-09-27 12:18:25 +02:00
Vedran Pavic
99fb17a66b Adapt to Spring WebSession API changes 2017-09-27 11:52:04 +02:00
Vedran Pavic
937b2fcbf1 Upgrade Gradle to 4.2 2017-09-25 09:06:06 +02:00
Vedran Pavic
9c5a7e9156 Upgrade Spring Boot to 2.0.0.M4
Closes gh-877
2017-09-15 22:13:23 +02:00
Vedran Pavic
4deccd3ad0 Upgrade Gradle to 4.1 2017-09-15 21:24:48 +02:00
Vedran Pavic
da058e9510 Upgrade dependencies to latest snapshots
- Reactor Bismuth-BUILD-SNAPSHOT
- Spring Framework 5.0.0.BUILD-SNAPSHOT
- Spring Data Kay-BUILD-SNAPSHOT
- Spring Security 5.0.0.BUILD-SNAPSHOT
2017-09-14 07:18:24 +02:00
Vedran Pavic
d28ca4658b Next development version 2017-09-14 07:16:49 +02:00
Rob Winch
c14fdb283d Release 2.0.0.M4 2017-09-13 18:04:06 -05:00
Rob Winch
ee1ff3ed3b Update Spring Security 5.0.0.M4 2017-09-13 18:03:33 -05:00
Vedran Pavic
eb7bcc5eeb Harmonize ReactorSessionRepository API
This commit renames the `ReactorSessionRepository#delete` to `deleteById` in order to make API consistent with `SessionRepository`.
2017-09-12 23:00:16 +02:00
Vedran Pavic
188e5ba4e0 Optimize JDBC session cleanup SQL statement
This commit improves session cleanup handling in  `JdbcOperationsSessionRepository#cleanUpExpiredSessions` by optimizing the used SQL statement. This is done by calculating the session expiry time when persisting the session, which in turn allows the cleanup SQL statement to be more index-friendly.

Closes gh-847
2017-09-12 15:41:10 -05:00
Vedran Pavic
1e46630467 Remove MapReactorSessionRepository default constructor
This commit removes the default `MapReactorSessionRepository` so that the users are required to explicitly supply the `Map` used to store the sessions.
2017-09-12 15:22:29 -05:00
Vedran Pavic
b72c600884 Upgrade dependencies to current milestones
- Reactor Bismuth-M4
- Spring Framework 5.0.0.RC4
- Spring Data Kay-RC3
- Lettuce 5.0.0.RC2
2017-09-12 07:54:14 +02:00
Vedran Pavic
274aec1691 Fix Boot based samples 2017-09-11 13:57:38 +02:00
Rob Winch
52ea98b4ce SpringWebSessionConfigurationTests close ApplicationContext 2017-09-07 20:12:45 -05:00
Rob Winch
5c294ae1d2 Polish 2017-09-07 20:12:45 -05:00
Greg Turnquist
1752928d96 Configure WebSessionManager's WebSessionIdResolver by bean definition
Allow a WebSessionIdResolver registered as a Spring bean to be wired into the WebSessionManager.
2017-09-07 20:12:45 -05:00
Vedran Pavic
0cdee25405 Remove MapSessionRepository default constructor
This commit removes the default `MapSessionRepository` constructor so that the users are required to explicitly supply the `Map` used to store the sessions.
2017-09-07 19:58:22 -05:00
Rob Winch
4a9f1700d5 Polish
Reorder methods
2017-09-06 15:12:13 -05:00
Rob Winch
36ab358d24 Remove SpringSessionWebSessionManager
Spring's DefaultWebSessionManager now supports all the functionality
that is needed for Spring Session, so we only need to implement
WebSessionStore
2017-09-06 14:50:48 -05:00
Vedran Pavic
8e3371aed9 Allow easier customization of cookie max age logic 2017-08-24 16:00:59 -05:00
mikemassa84
2161f966de Update grails3.adoc
Add a note about spring-session and grails flash scope, with link to stackoverflow answer.
2017-08-24 14:37:32 -05:00
Vedran Pavic
63b67a501d Update guides for Redis based samples 2017-08-24 14:17:10 -05:00
Vedran Pavic
2b0431eae4 Use TestContainers for Gretty integration tests 2017-08-24 14:17:10 -05:00
Vedran Pavic
04ec086014 Use TestContainers for integration tests 2017-08-24 14:17:10 -05:00
Rob Winch
5697f49a71 Config->HelloWebfluxSessionConfig
Use a more meaningful name
2017-08-24 13:54:21 -05:00
Rob Winch
dfce66383f webflux sample uses @EnableSpringWebSession
Issue gh-861
2017-08-24 13:52:52 -05:00
Rob Winch
a83e59bf52 Polish
Fix checkstyle

Issue gh-861
2017-08-24 13:52:24 -05:00
Greg Turnquist
8b233e84ef Create @EnableSpringWebSession annotation. 2017-08-24 13:41:42 -05:00
Greg Turnquist
84e7fbace1 Fix MapReactorSessionRepository's delete(). 2017-08-24 13:40:57 -05:00
Rob Winch
f455df3333 Add WebFlux sample
Fixesh gh-857
2017-08-18 16:28:46 -05:00
Rob Winch
a7bb9d3b31 SpringSessionWebSessionManager writes on commit
when the ServerHttpResonse is commited the cookie and the session are written

Fixes gh-856
2017-08-18 16:28:46 -05:00
Kanjie Lu
5f0e4c3b85 fix typo
change "they key" to  "the key"
2017-08-05 20:39:08 -05:00
Vedran Pavic
23c6c7cf31 Upgrade Spring Boot to 2.0.0.M3
Closes gh-841
2017-07-27 14:08:48 +02:00
Vedran Pavic
c8c5fae678 Polish build 2017-07-26 08:49:45 +02:00
Vedran Pavic
f4a58622e4 Upgrade dependencies to latest snapshots
- Reactor Bismuth-BUILD-SNAPSHOT
- Spring Framework 5.0.0.BUILD-SNAPSHOT
- Spring Data Kay-BUILD-SNAPSHOT
- Spring Security 5.0.0.BUILD-SNAPSHOT
2017-07-26 08:47:23 +02:00
Joe Grandja
5384764021 Next development version 2017-07-25 10:12:45 -04:00
Joe Grandja
56033a9b68 Release version 2.0.0.M3 2017-07-25 09:31:12 -04:00
Vedran Pavic
99a2b079ac Upgrade dependencies to current milestones
- Spring Framework 5.0.0.RC3
- Spring Data Kay-RC1
- Spring Security 5.0.0.M3
2017-07-25 10:11:26 +02:00
Vedran Pavic
9120151692 Polish "Add WebFlux Support"
Closes gh-683
2017-07-21 15:31:45 +02:00
Rob Winch
5abbe66b1d Add WebFlux Support 2017-07-21 15:30:19 +02:00
Rob Winch
f00c196430 Update Dependencies to Prepare Release 2017-07-20 22:24:35 -05:00
Rob Winch
be2604ca69 Add Session.changeSessionId 2017-07-20 16:31:38 -05:00
Rob Winch
2aa71ffb6d Update to lettuce 5.0.0.RC1 2017-07-20 09:54:53 -05:00
Rob Winch
8bdcba6e50 Spring Session 2.0.0.M2 w/ Boot Samples
This is necessary because the current version of Spring Session is not
compatible with Boot 2.0.0.M2 and we cannot release against the SNAPSHOTs

Issue gh-833
2017-07-18 20:09:21 -05:00
Mark Paluch
8dd1a10f1b Adapt to changes in Spring Data Redis API 2017-07-18 16:19:05 +02:00
Vedran Pavic
1d247aa96f Align Checkstyle config with spring-build-conventions 2017-07-12 08:24:09 +02:00
Vedran Pavic
c00d6a7bf2 Apply correct convention plugin for modules 2017-07-10 09:10:33 +02:00
Vedran Pavic
c0df3bf28b Fix deprecation warnings 2017-07-10 07:28:09 +02:00
Vedran Pavic
1b8c9838a4 Fix unchecked operations build warning 2017-07-10 07:27:27 +02:00
Vedran Pavic
8a1b454121 Fix javadoc build warning 2017-07-10 07:26:35 +02:00
Vedran Pavic
ef69c8169a Polish dependencies
This commit removes needless dependency exclusions.

See gh-824
2017-07-10 07:20:35 +02:00
Rob Winch
40b3d07224 Revert "Add --debug to Jenkinsfile"
This reverts commit 9c4e20f074.
2017-07-07 11:23:54 -05:00
Rob Winch
8c726f2215 Use Gradle 3.5.1
This works around a bug in 4.0 where Gradle is hanging when trying to
resolve a configuration.
2017-07-07 11:17:32 -05:00
Rob Winch
c2a86a27ce Travis skip install 2017-07-07 10:16:13 -05:00
Rob Winch
6a08ef6f97 Polish travis build 2017-07-07 10:03:54 -05:00
Rob Winch
9c4e20f074 Add --debug to Jenkinsfile
Try and troubleshoot why the build is hanging
2017-07-07 09:42:24 -05:00
Vedran Pavic
5845a9c46a Improve dependency management
This commit improves dependency management with the following changes:

 - `spring-session-core`: move `javax.servlet-api` from `provided` to `optional` configuration due to introduction of reactive support
 - `spring-session-data-redis`: remove Redis driver from `compile` configuration
 - Boot samples: delegate Redis driver choice to `spring-boot-starter-data-redis`
 - polish `test` configuration dependencies
2017-07-06 17:05:01 -05:00
Rob Winch
7c6693a268 Remove Sonar to see if it fixes build 2017-07-06 08:49:21 -05:00
Vedran Pavic
05a3f59813 Simplify Hazelcast sample 2017-07-05 16:00:28 -05:00
Vedran Pavic
47a7a35aa4 Remove use of Assert#notNull from core components
Fixes gh-820
2017-07-05 17:04:03 +02:00
Vedran Pavic
04b4fe3e3b Fix Checkstyle violations 2017-07-01 00:04:46 +02:00
Rob Winch
36bb65e4b5 Add default methods to Session
Fixes gh-819
2017-06-30 10:25:14 -05:00
Rob Winch
8ef36e4f3e Session Optional<T> getAttribute -> T getAttribute
Issue gh-819
2017-06-30 10:24:59 -05:00
Rob Winch
ab3e280993 Update to latest SNAPSHOTs 2017-06-29 22:20:26 -05:00
Rob Winch
30562b5749 Use Spring IO Cairo-BUILD-SNAPSHOT 2017-06-27 16:37:13 -05:00
Rob Winch
d42a7b65ea Add MapReactorSessionRepository
Fixes gh-815
2017-06-27 16:32:51 -05:00
Rob Winch
db9807d12b Add ReactorSessionRepository
Fixes gh-814
2017-06-27 16:32:51 -05:00
Rob Winch
db09fa8168 Use SPRING_SESSION_TEAM_EMAILS 2017-06-26 10:52:17 -05:00
Vedran Pavic
031541bc05 Fix Checkstyle violations 2017-06-26 08:45:20 +02:00
Vedran Pavic
084e3428fb Move SessionEventRegistry back to integration-test sources
Fixes gh-810
2017-06-23 19:03:46 +02:00
Vedran Pavic
b321ff02f0 Revert "SessionRepository.save returns S"
See gh-809
2017-06-23 18:48:30 +02:00
Rob Winch
c6c6beb40c Session.delete -> deleteById
Fixes gh-809
2017-06-22 21:30:14 -05:00
Rob Winch
0127ef9f9b SessionRepository.getSession(String) -> findById(String)
Issue gh-809
2017-06-22 21:29:34 -05:00
Rob Winch
cd8686ae9c SessionRepository.save returns S
Issue gh-809
2017-06-22 21:27:25 -05:00
Rob Winch
233d179bfa Revert "Allow Publishing When Spring IO Fails"
This reverts commit fca411996a.
2017-06-22 13:20:23 -05:00
Rob Winch
4e8ae8d9d4 Revert "Deploy Without Checks for Spring IO"
This reverts commit 8c6810c6dd.
2017-06-22 13:20:21 -05:00
Rob Winch
8c6810c6dd Deploy Without Checks for Spring IO 2017-06-22 13:18:01 -05:00
Rob Winch
fca411996a Allow Publishing When Spring IO Fails
This is necessary to solve the problem of chicken and the Egg. See
https://github.com/spring-io/platform/issues/622#issuecomment-310452646
2017-06-22 13:00:12 -05:00
Rob Winch
79b8296e1c Work Around spring-projects/spring-boot#9573
Issue gh-806
2017-06-22 09:04:23 -05:00
Rob Winch
043cb42149 Extract spring-session-jdbc
Issue gh-806
2017-06-22 09:04:09 -05:00
Rob Winch
c28f047eb5 Extract spring-session-data-hazelcast
Issue gh-806
2017-06-22 09:03:50 -05:00
Rob Winch
972cf66d7e Extract spring-session-data-redis
Issue gh-806
2017-06-22 09:03:25 -05:00
Rob Winch
f1319483ee Move spring-session to spring-session-core
Issue gh-806
2017-06-22 09:02:44 -05:00
Rob Winch
6ad5006280 Update to Gradle 4.0 2017-06-16 13:40:43 -05:00
Vedran Pavic
f7e07b7f6b Improve Session API to use Java 8 2017-06-16 11:44:19 -05:00
Vedran Pavic
4cf26d9c36 Move ExpiringSession API into Session 2017-06-16 11:44:19 -05:00
Vedran Pavic
a848df1235 Replace explicit type arguments with diamond operator 2017-06-16 11:44:19 -05:00
Rob Winch
f8292ba512 Update to Spring Boot 2.0.0.M2
Fixes gh-801
2017-06-16 10:29:30 -05:00
Rob Winch
21bcc6e8d7 Next Development Version 2017-06-15 20:35:20 -05:00
450 changed files with 15228 additions and 8764 deletions

19
.editorconfig Normal file
View File

@@ -0,0 +1,19 @@
root = true
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 120
[*.java]
indent_style = tab
indent_size = 4
charset = latin1
continuation_indent_size = 8
[*.xml]
indent_style = tab
indent_size = 4
charset = latin1
continuation_indent_size = 8

View File

@@ -1,3 +1,7 @@
<!--
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
-->
<!--
Thanks for raising a Spring Session issue. Please provide a brief description of your problem along with the version of Spring Session that you are using. If possible, please also consider putting together a sample application that reproduces the issue.
-->

View File

@@ -1,3 +1,7 @@
<!--
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
-->
<!--
Thanks for contributing to Spring Session. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with #).
-->

2
.gitignore vendored
View File

@@ -10,6 +10,6 @@ target
out
.springBeans
*.rdb
!eclispe/.checkstyle
.checkstyle
!etc/eclipse/.checkstyle
!**/src/**/build

View File

@@ -1,19 +1,20 @@
language: java
services:
- redis-server
sudo: required
jdk:
- oraclejdk8
services: docker
os:
- linux
jdk: oraclejdk8
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
script: ./gradlew build
install: true
script: ./gradlew clean build --refresh-dependencies --no-daemon

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

150
Jenkinsfile vendored
View File

@@ -1,9 +1,9 @@
def projectProperties = [
[$class: 'BuildDiscarderProperty',
strategy: [$class: 'LogRotator', numToKeepStr: '5']],
pipelineTriggers([cron('@daily')])
]
properties(projectProperties)
properties([
buildDiscarder(logRotator(numToKeepStr: '10')),
pipelineTriggers([
cron('@daily')
]),
])
def SUCCESS = hudson.model.Result.SUCCESS.toString()
currentBuild.result = SUCCESS
@@ -11,57 +11,97 @@ currentBuild.result = SUCCESS
try {
parallel check: {
stage('Check') {
node {
checkout scm
try {
sh "./gradlew clean check --refresh-dependencies --no-daemon"
} catch(Exception e) {
currentBuild.result = 'FAILED: check'
throw e
} finally {
junit '**/build/*-results/*.xml'
timeout(time: 45, unit: 'MINUTES') {
node('ubuntu1804') {
checkout scm
try {
sh './gradlew clean check --no-daemon --refresh-dependencies'
}
catch (e) {
currentBuild.result = 'FAILED: check'
throw e
}
finally {
junit '**/build/test-results/*/*.xml'
}
}
}
}
},
sonar: {
stage('Sonar') {
node {
checkout scm
withCredentials([string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')]) {
jdk9: {
stage('JDK 9') {
timeout(time: 45, unit: 'MINUTES') {
node {
checkout scm
try {
sh "./gradlew clean sonarqube -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon"
} catch(Exception e) {
currentBuild.result = 'FAILED: sonar'
withEnv(["JAVA_HOME=${tool 'jdk9'}"]) {
sh './gradlew clean test --no-daemon --refresh-dependencies'
}
}
catch (e) {
currentBuild.result = 'FAILED: jdk9'
throw e
}
}
}
}
},
springio: {
stage('Spring IO') {
node {
checkout scm
try {
sh "./gradlew clean springIoCheck -PplatformVersion=Cairo-BUILD-SNAPSHOT -PexcludeProjects='**/samples/**' --refresh-dependencies --no-daemon --stacktrace"
} catch(Exception e) {
currentBuild.result = 'FAILED: springio'
throw e
} finally {
junit '**/build/spring-io*-results/*.xml'
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
}
}
}
}
}
if(currentBuild.result == 'SUCCESS') {
parallel artifactory: {
stage('Artifactory Deploy') {
if (currentBuild.result == 'SUCCESS') {
parallel artifacts: {
stage('Deploy Artifacts') {
node {
checkout scm
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
sh "./gradlew artifactoryPublish -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --no-daemon --stacktrace"
try {
withCredentials([file(credentialsId: 'spring-signing-secring.gpg', variable: 'SIGNING_KEYRING_FILE')]) {
withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) {
withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) {
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
sh './gradlew deployArtifacts finalizeDeployArtifacts --stacktrace --no-daemon --refresh-dependencies -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password=$SIGNING_PASSWORD -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD'
}
}
}
}
}
catch (e) {
currentBuild.result = 'FAILED: artifacts'
throw e
}
}
}
@@ -70,32 +110,38 @@ try {
stage('Deploy Docs') {
node {
checkout scm
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
try {
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
sh './gradlew deployDocs --stacktrace --no-daemon --refresh-dependencies -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME'
}
}
catch (e) {
currentBuild.result = 'FAILED: docs'
throw e
}
}
}
}
}
} finally {
}
finally {
def buildStatus = currentBuild.result
def buildNotSuccess = !SUCCESS.equals(buildStatus)
def buildNotSuccess = !SUCCESS.equals(buildStatus)
def lastBuildNotSuccess = !SUCCESS.equals(currentBuild.previousBuild?.result)
if(buildNotSuccess || lastBuildNotSuccess) {
stage('Notifiy') {
if (buildNotSuccess || lastBuildNotSuccess) {
stage('Notify') {
node {
final def RECIPIENTS = [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']]
def subject = "${buildStatus}: Build ${env.JOB_NAME} ${env.BUILD_NUMBER} status is now ${buildStatus}"
def details = """The build status changed to ${buildStatus}. For details see ${env.BUILD_URL}"""
def details = "The build status changed to ${buildStatus}. For details see ${env.BUILD_URL}"
emailext (
subject: subject,
body: details,
recipientProviders: RECIPIENTS,
to: "$SPRING_SECURITY_TEAM_EMAILS"
emailext(
subject: subject,
body: details,
recipientProviders: RECIPIENTS,
to: "$SPRING_SESSION_TEAM_EMAILS"
)
}
}

202
LICENSE.txt Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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
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,
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.

View File

@@ -1,26 +1,32 @@
image:https://badges.gitter.im/spring-projects/spring-session.svg[link="https://gitter.im/spring-projects/spring-session?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
image:https://travis-ci.org/spring-projects/spring-session.svg?branch=master["Build Status", link="https://travis-ci.org/spring-projects/spring-session"]
= Spring Session
Rob Winch
Spring Session aims to provide a common infrastructure for managing sessions. This provides many benefits including:
image:https://travis-ci.org/spring-projects/spring-session.svg?branch=master["Build Status", link="https://travis-ci.org/spring-projects/spring-session"] image:https://badges.gitter.im/spring-projects/spring-session.svg[link="https://gitter.im/spring-projects/spring-session?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
* Accessing a session from any environment (i.e. web, messaging infrastructure, etc)
* In a web environment
** Support for clustering in a vendor neutral way
** Pluggable strategy for determining the session id
** Easily keep the HttpSession alive when a WebSocket is active
Spring Session provides an API and implementations for managing a user's session information, while also making it trivial to support clustered sessions without being tied to an application container specific solution.
It also provides transparent integration with:
* `HttpSession` - allows replacing the `HttpSession` in an application container (i.e. Tomcat) neutral way, with support for providing session IDs in headers to work with RESTful APIs.
* `WebSocket` - provides the ability to keep the `HttpSession` alive when receiving WebSocket messages
* `WebSession` - allows replacing the Spring WebFlux's `WebSession` in an application container neutral way.
== Modules
Spring Session consists of the following modules:
* Spring Session Core - provides core Spring Session functionalities and APIs
* Spring Session Data Redis - provides `SessionRepository` and `ReactiveSessionRepository` implementation backed by Redis and configuration support
* Spring Session JDBC - provides `SessionRepository` implementation backed by a relational database and configuration support
* Spring Session Hazelcast - provides `SessionRepository` implementation backed by Hazelcast and configuration support
== Code of Conduct
This project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct].
By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
= Spring Session Project Site
== 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
== 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,21 +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.2.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/libs-snapshot' }
maven { url 'https://repo.spring.io/plugins-snapshot' }
}
}
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

@@ -1,166 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<!-- Suppressions -->
<module name="SuppressionFilter">
<property name="file" value="${configDir}/suppressions.xml"/>
</module>
<!-- Root Checks -->
<module name="RegexpHeader">
<property name="headerFile" value="${configDir}/header.txt"/>
<property name="fileExtensions" value="java"/>
</module>
<module name="NewlineAtEndOfFile">
<property name="lineSeparator" value="lf"/>
<property name="fileExtensions" value="java,xml"/>
</module>
<!-- TreeWalker Checks -->
<module name="TreeWalker">
<!-- Annotations -->
<module name="AnnotationUseStyle">
<property name="elementStyle" value="compact"/>
</module>
<module name="MissingOverride"/>
<module name="PackageAnnotation"/>
<module name="AnnotationLocation">
<property name="allowSamelineSingleParameterlessAnnotation" value="false" />
</module>
<!-- Block Checks -->
<module name="EmptyBlock">
<property name="option" value="text"/>
</module>
<module name="LeftCurly"/>
<module name="RightCurly">
<property name="option" value="alone"/>
</module>
<module name="NeedBraces"/>
<module name="AvoidNestedBlocks"/>
<!-- Class Design -->
<module name="FinalClass"/>
<module name="InterfaceIsType"/>
<module name="HideUtilityClassConstructor"/>
<module name="MutableException"/>
<module name="InnerTypeLast"/>
<module name="OneTopLevelClass"/>
<!-- Coding -->
<module name="CovariantEquals"/>
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="InnerAssignment"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<module name="StringLiteralEquality"/>
<module name="NestedForDepth">
<property name="max" value="3"/>
</module>
<module name="NestedIfDepth">
<property name="max" value="3"/>
</module>
<module name="NestedTryDepth">
<property name="max" value="3"/>
</module>
<module name="MultipleVariableDeclarations"/>
<module name="RequireThis">
<property name="checkMethods" value="false"/>
</module>
<module name="OneStatementPerLine"/>
<!-- Imports -->
<module name="AvoidStarImport"/>
<module name="AvoidStaticImport">
<property name="excludes"
value="org.assertj.core.api.Assertions.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.AdditionalMatchers.*, org.mockito.ArgumentMatchers.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultHandlers.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo"/>
</module>
<module name="IllegalImport"/>
<module name="RedundantImport"/>
<module name="UnusedImports">
<property name="processJavadoc" value="true"/>
</module>
<module name="ImportOrder">
<property name="groups" value="java,/^javax?\./,*,org.springframework"/>
<property name="ordered" value="true"/>
<property name="separated" value="true"/>
<property name="option" value="bottom"/>
<property name="sortStaticImportsAlphabetically" value="true"/>
</module>
<!-- Javadoc Comments -->
<module name="JavadocType">
<property name="scope" value="package"/>
<property name="authorFormat" value=".+\s.+"/>
</module>
<module name="JavadocMethod">
<property name="allowMissingJavadoc" value="true"/>
</module>
<module name="JavadocVariable">
<property name="scope" value="public"/>
</module>
<module name="JavadocStyle">
<property name="checkEmptyJavadoc" value="true"/>
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="JavadocTagContinuationIndentation">
<property name="offset" value="0"/>
</module>
<module name="AtclauseOrder">
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF"/>
<property name="tagOrder" value="@param, @author, @since, @see, @version, @serial, @deprecated"/>
</module>
<module name="AtclauseOrder">
<property name="target" value="METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
<property name="tagOrder" value="@param, @return, @throws, @since, @deprecated, @see"/>
</module>
<!-- Miscellaneous -->
<module name="CommentsIndentation"/>
<module name="UpperEll"/>
<module name="ArrayTypeStyle"/>
<module name="OuterTypeFilename"/>
<!-- Modifiers -->
<module name="RedundantModifier"/>
<!-- Regexp -->
<module name="RegexpSinglelineJava">
<property name="format" value="^\t* +\t*\S"/>
<property name="message" value="Line has leading space characters; indentation should be performed with tabs only."/>
<property name="ignoreComments" value="true"/>
</module>
<module name="RegexpSinglelineJava">
<property name="maximum" value="0"/>
<property name="format" value="org\.mockito\.Mockito\.(when|doThrow|doAnswer)"/>
<property name="message"
value="Please use BDDMockto imports."/>
<property name="ignoreComments" value="true"/>
</module>
<module name="RegexpSinglelineJava">
<property name="maximum" value="0"/>
<property name="format" value="org\.junit\.Assert\.assert"/>
<property name="message" value="Please use AssertJ imports."/>
<property name="ignoreComments" value="true"/>
</module>
<module name="Regexp">
<property name="format" value="[ \t]+$"/>
<property name="illegalPattern" value="true"/>
<property name="message" value="Trailing whitespace"/>
</module>
<!-- Whitespace -->
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter">
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS, ARRAY_DECLARATOR"/>
</module>
<module name="NoWhitespaceBefore"/>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
</module>
</module>

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,18 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<suppress files=".+Application\.java" checks="HideUtilityClassConstructor"/>
<suppress files=".+Configuration\.java" checks="HideUtilityClassConstructor"/>
<suppress files="[\\/]src[\\/]test[\\/]java[\\/]" checks="Javadoc"/>
<suppress files="[\\/]src[\\/]integration-test[\\/]java[\\/]" checks="Javadoc"/>
<suppress files="[\\/]docs[\\/]" checks="Javadoc"/>
<suppress files="[\\/]docs[\\/]" checks="CommentsIndentation"/>
<suppress files="[\\/]docs[\\/]" checks="InnerTypeLast"/>
<suppress files="[\\/]samples[\\/]" checks="Javadoc"/>
<suppress files="[\\/]samples[\\/]" checks="CommentsIndentation"/>
<suppress files="[\\/]samples[\\/]" checks="InnerTypeLast"/>
</suppressions>

View File

@@ -2,22 +2,24 @@ apply plugin: 'io.spring.convention.docs'
apply plugin: 'io.spring.convention.spring-test'
dependencies {
testCompile project(':spring-session')
testCompile project(':spring-session-core')
testCompile project(':spring-session-data-redis')
testCompile "org.springframework:spring-jdbc"
testCompile "org.springframework:spring-messaging"
testCompile "org.springframework:spring-webmvc"
testCompile "org.springframework:spring-websocket"
testCompile "org.springframework.security:spring-security-config"
testCompile "org.springframework.security:spring-security-web"
testCompile "org.springframework.security:spring-security-test"
testCompile "junit:junit"
testCompile "org.mockito:mockito-core"
testCompile "org.springframework:spring-test"
testCompile "org.assertj:assertj-core"
testCompile "com.hazelcast:hazelcast"
testCompile "io.lettuce:lettuce-core"
testCompile "javax.servlet:javax.servlet-api"
testCompile project(':spring-session-hazelcast')
testCompile project(':spring-session-jdbc')
testCompile 'org.springframework:spring-jdbc'
testCompile 'org.springframework:spring-messaging'
testCompile 'org.springframework:spring-webmvc'
testCompile 'org.springframework:spring-websocket'
testCompile 'org.springframework.security:spring-security-config'
testCompile 'org.springframework.security:spring-security-web'
testCompile 'org.springframework.security:spring-security-test'
testCompile 'junit:junit'
testCompile 'org.mockito:mockito-core'
testCompile 'org.springframework:spring-test'
testCompile 'org.assertj:assertj-core'
testCompile 'com.hazelcast:hazelcast'
testCompile 'io.lettuce:lettuce-core'
testCompile 'javax.servlet:javax.servlet-api'
}
def versions = dependencyManagement.managedVersions
@@ -25,19 +27,23 @@ def versions = dependencyManagement.managedVersions
asciidoctor {
def ghTag = snapshotBuild ? 'master' : project.version
def ghUrl = "https://github.com/spring-projects/spring-session/tree/$ghTag"
attributes 'version-snapshot': snapshotBuild,
attributes 'docs-itest-dir': "$rootProject.projectDir.path/docs/src/integration-test/java/",
'docs-test-dir': "$rootProject.projectDir.path/docs/src/test/java/",
'docs-test-resources-dir': "$rootProject.projectDir.path/docs/src/test/resources/",
'download-url': "https://github.com/spring-projects/spring-session/archive/${ghTag}.zip",
'gh-samples-url': "$ghUrl/samples/",
'gh-url': ghUrl,
'hazelcast-version': versions['com.hazelcast:hazelcast'],
'lettuce-version': versions['io.lettuce:lettuce-core'],
'samples-dir': "$rootProject.projectDir.path/samples/",
'session-jdbc-main-resources-dir': "${project(':spring-session-jdbc').projectDir.path}/src/main/resources/",
'spring-boot-version': project.springBootVersion,
'spring-data-redis-version': versions['org.springframework.data:spring-data-redis'],
'spring-framework-version': versions['org.springframework:spring-core'],
'spring-security-version': versions['org.springframework.security:spring-security-core'],
'spring-session-version': project.version,
'version-milestone': milestoneBuild,
'version-release': releaseBuild,
'gh-url': ghUrl,
'gh-samples-url': "$ghUrl/samples/",
'download-url' : "https://github.com/spring-projects/spring-session/archive/${ghTag}.zip",
'spring-session-version' : version,
'spring-version' : versions['org.springframework:spring-core'],
'lettuce-version' : versions['io.lettuce:lettuce-core'],
'hazelcast-version' : versions['com.hazelcast:hazelcast'],
'docs-itest-dir' : rootProject.projectDir.path + '/docs/src/integration-test/java/',
'docs-test-dir' : rootProject.projectDir.path + '/docs/src/test/java/',
'docs-test-resources-dir' : rootProject.projectDir.path + '/docs/src/test/resources/',
'samples-dir' : rootProject.projectDir.path + '/samples/',
'session-main-resources-dir' : rootProject.projectDir.path + '/spring-session/src/main/resources/'
'version-snapshot': snapshotBuild
}

View File

@@ -4,136 +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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `JedisConnectionFactory` to point to a Redis server.
----
$ ./gradlew :spring-session-sample-boot-findbyusername:bootRun
----
====
----
$ ./gradlew :samples:findbyusername: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
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
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.session.timeout= # Session timeout in seconds.
spring.session.jdbc.initializer.enabled= # Create the required session tables on startup if necessary. Enabled automatically if the default table name is set or a custom schema is configured.
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 database table used to store sessions.
spring.session.jdbc.table-name=SPRING_SESSION # Name of the database table used to store sessions.
----
====
For more information, refer to http://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:postgresql://localhost:5432/myapp
spring.datasource.username=myapp
spring.datasource.password=secret
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 http://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 :samples:httpsession-jdbc-boot:bootRun
$ ./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://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[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,113 +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
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.session.timeout= # Session timeout in seconds.
spring.session.redis.flush-mode= # Sessions flush mode.
spring.session.redis.namespace= # Namespace for keys used to store sessions.
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 http://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
spring.redis.password=secret
spring.redis.port=6379
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 http://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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `JedisConnectionFactory` to point to a Redis server.
----
$ ./gradlew :spring-session-sample-boot-redis:bootRun
----
====
----
$ ./gradlew :samples:boot: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://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[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 http://redis.io/topics/quickstart[installing redis-cli].
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 extend `AbstractWebSocketMessageBrokerConfigurer`.
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 extending `AbstractWebSocketMessageBrokerConfigurer` 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,86 +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.session.timeout=60
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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
----
$ ./gradlew :samples:websocket: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 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 http://docs.spring.io/spring-boot/docs/current/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,48 +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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `JedisConnectionFactory` to point to a Redis server.
====
----
$ ./gradlew :spring-session-sample-misc-grails3:bootRun
----
----
$ ./gradlew :samples: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://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[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 http://redis.io/topics/quickstart[installing redis-cli].
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 does not work with Grails flash scope without additional work.
See https://stackoverflow.com/a/43311427 for an explanation.

View File

@@ -3,99 +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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
----
$ ./gradlew :spring-session-sample-javaconfig-custom-cookie:tomcatRun
----
====
----
$ ./gradlew :samples: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"]
@@ -26,15 +28,17 @@ If you are using Maven, ensure to add the following dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>{spring-version}</version>
<version>{spring-framework-version}</version>
</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/latest/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/latest/manual/html-single/index.html#hazelcast-configuration[reference documentation].
----
$ ./gradlew :spring-session-sample-javaconfig-hazelcast:tomcatRun
----
====
----
$ ./gradlew :samples:hazelcast-spring: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://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[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/latest/manual/html-single/index.html#hazelcast-java-client[a Java client],
http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#other-client-implementations[one of the other clients], or the
http://docs.hazelcast.org/docs/latest/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/latest/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/latest/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"]
@@ -26,15 +28,17 @@ If you are using Maven, ensure to add the following dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>{spring-version}</version>
<version>{spring-framework-version}</version>
</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 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.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 :samples:httpsession-jdbc:tomcatRun
$ ./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://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[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"]
@@ -31,15 +33,17 @@ If you are using Maven, ensure to add the following dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>{spring-version}</version>
<version>{spring-framework-version}</version>
</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 http://docs.spring.io/spring-data/data-redis/docs/current/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,53 +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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
----
$ ./gradlew :spring-session-sample-javaconfig-redis:tomcatRun
----
====
----
$ ./gradlew :samples:httpsession: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://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[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 http://redis.io/topics/quickstart[installing redis-cli].
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"]
@@ -31,15 +33,17 @@ If you are using Maven, ensure to add the following dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>{spring-version}</version>
<version>{spring-framework-version}</version>
</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,82 +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 http://docs.spring.io/spring-data/data-redis/docs/current/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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
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 :samples:rest:tomcatRun
$ ./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
...
@@ -158,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
...
@@ -203,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 http://redis.io/topics/quickstart[installing redis-cli].
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"]
@@ -32,15 +33,17 @@ If you are using Maven, ensure to add the following dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>{spring-version}</version>
<version>{spring-framework-version}</version>
</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,106 +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 http://docs.spring.io/spring-data/data-redis/docs/current/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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
----
$ ./gradlew :spring-session-sample-javaconfig-security:tomcatRun
----
====
----
$ ./gradlew :samples: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://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[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 http://redis.io/topics/quickstart[installing redis-cli].
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

@@ -1,161 +0,0 @@
= Spring Session - Multiple Sessions
Rob Winch
:toc:
This guide describes how to use Spring Session to manage multiple simultaneous browser sessions (i.e Google Accounts).
== Integrating with Spring Session
The steps to integrate with Spring Session are exactly the same as those outline in the link:httpsession.html[HttpSession Guide], so we will skip to running the sample application.
[[users-sample]]
== users Sample Application
The users application demonstrates how to allow an application to manage multiple simultaneous browser sessions (i.e. Google Accounts).
=== Running the users 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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
----
$ ./gradlew :samples:users:tomcatRun
----
You should now be able to access the application at http://localhost:8080/
=== Exploring the users Sample Application
Try using the application. Authenticate with the following information:
* **Username** _rob_
* **Password** _rob_
Now click the **Login** button. You should now be authenticated as the user **rob**.
We can click on links and our user information is preserved.
* Click on the **Link** link in the navigation bar at the top
* Observe we are still authenticated as **rob**
Let's add an another account.
* Return to the *Home* page
* Click on the arrow next to *rob* in the upper right hand corner
* Click **Add Account**
The log in form is displayed again. Authenticate with the following information:
* **Username** _luke_
* **Password** _luke_
Now click the **Login** button. You should now be authenticated as the user **luke**.
We can click on links and our user information is preserved.
* Click on the **Link** link in the navigation bar at the top
* Observe we are still authenticated as **luke**
Where did our original user go? Let's switch to our original account.
* Click on the arrow next to *luke* in the upper right hand corner.
* Click on **Switch Account** -> *rob*
We are now using the session associated with *rob*.
== How does it work?
// tag::how-does-it-work[]
Let's take a look at how Spring Session keeps track of multiple sessions.
=== Managing a Single Session
Spring Session keeps track of the `HttpSession` by adding a value to a cookie named SESSION.
For example, the SESSION cookie might have a value of:
7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
=== Adding a Session
We can add another session by requesting a URL that contains a special parameter in it.
By default the parameter name is *_s*. For example, the following URL would create a new session:
http://localhost:8080/?_s=1
NOTE: The parameter value does not indicate the actual session id.
This is important because we never want to allow the session id to be determined by a client to avoid https://www.owasp.org/index.php/Session_fixation[session fixation attacks].
Additionally, we do not want the session id to be leaked since it is sent as a query parameter.
Remember sensitive information should only be transmitted as a header or in the body of the request.
Rather than creating the URL ourselves, we can utilize the `HttpSessionManager` to do this for us.
We can obtain the `HttpSessionManager` from the `HttpServletRequest` using the following:
.src/main/java/sample/UserAccountsFilter.java
[source,java,indent=0]
----
include::{samples-dir}javaconfig/users/src/main/java/sample/UserAccountsFilter.java[tags=HttpSessionManager]
----
We can now use it to create a URL to add another session.
.src/main/java/sample/UserAccountsFilter.java
[source,java,indent=0]
----
include::{samples-dir}javaconfig/users/src/main/java/sample/UserAccountsFilter.java[tags=addAccountUrl]
----
<1> We have an existing variable named `unauthenticatedAlias`.
The value is an alias that points to an existing unauthenticated session.
If no such session exists, the value is null.
This ensures if we have an existing unauthenticated session that we use it instead of creating a new session.
<2> If all of our sessions are already associated to a user, we create a new session alias.
<3> If there is an existing session that is not associated to a user, we use its session alias.
<4> Finally, we create the add account URL.
The URL contains a session alias that either points to an existing unauthenticated session or is an alias that is unused thus signaling to create a new session associated to that alias.
Now our SESSION cookie looks something like this:
0 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e 1 1d526d4a-c462-45a4-93d9-84a39b6d44ad
Such that:
* There is a session with the id *7e8383a4-082c-4ffe-a4bc-c40fd3363c5e*
** The alias for this session is *0*.
For example, if the URL is http://localhost:8080/?_s=0 this alias would be used.
** This is the default session.
This means that if no session alias is specified, then this session is used.
For example, if the URL is http://localhost:8080/ this session would be used.
* There is a session with the id *1d526d4a-c462-45a4-93d9-84a39b6d44ad*
** The alias for this session is *1*.
If the session alias is *1*, then this session is used.
For example, if the URL is http://localhost:8080/?_s=1 this alias would be used.
=== Automatic Session Alias Inclusion with encodeURL
The nice thing about specifying the session alias in the URL is that we can have multiple tabs open with different active sessions.
The bad thing is that we need to include the session alias in every URL of our application.
Fortunately, Spring Session will automatically include the session alias in any URL that passes through http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#encodeURL(java.lang.String)[HttpServletResponse#encodeURL(java.lang.String)]
This means that if you are using standard tag libraries the session alias is automatically included in the URL.
For example, if we are currently using the session with the alias of *1*, then the following:
.src/main/webapp/index.jsp
[source,xml,indent=0]
----
include::{samples-dir}javaconfig/users/src/main/webapp/index.jsp[tags=link]
----
will output a link of:
[source,html]
----
<a id="navLink" href="/link.jsp?_s=1">Link</a>
----
// end::how-does-it-work[]

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"]
@@ -26,15 +28,17 @@ If you are using Maven, ensure to add the following dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>{spring-version}</version>
<version>{spring-framework-version}</version>
</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 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.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 http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#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 http://docs.spring.io/spring-framework/docs/current/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 :samples:httpsession-jdbc-xml:tomcatRun
$ ./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://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[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"]
@@ -31,15 +32,17 @@ If you are using Maven, ensure to add the following dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>{spring-version}</version>
<version>{spring-framework-version}</version>
</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 http://docs.spring.io/spring-data/data-redis/docs/current/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,82 +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 http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#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 http://docs.spring.io/spring-framework/docs/current/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 http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
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 :samples:httpsession-xml:tomcatRun
$ ./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://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[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 http://redis.io/topics/quickstart[installing redis-cli].
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

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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,
@@ -52,9 +52,7 @@ public class FindByIndexNameSessionRepositoryTests {
// tag::findby-username[]
String username = "username";
Map<String, Session> sessionIdToSession = this.sessionRepository
.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
username);
.findByPrincipalName(username);
// end::findby-username[]
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2017 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,
@@ -21,10 +21,10 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.session.ExpiringSession;
import org.springframework.session.Session;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
@@ -33,12 +33,12 @@ import static org.mockito.Mockito.mock;
/**
* @author Rob Winch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(SpringRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class HttpSessionConfigurationNoOpConfigureRedisActionXmlTests {
@Autowired
SessionRepositoryFilter<? extends ExpiringSession> filter;
SessionRepositoryFilter<? extends Session> filter;
@Test
public void redisConnectionFactoryNotUsedSinceNoValidation() {

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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,
@@ -16,21 +16,28 @@
package docs;
import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import com.hazelcast.config.Config;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import org.junit.Test;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.mock.web.MockServletContext;
import org.springframework.session.ExpiringSession;
import org.springframework.session.MapSession;
import org.springframework.session.MapSessionRepository;
import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.redis.ReactiveRedisOperationsSessionRepository;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.hazelcast.HazelcastSessionRepository;
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
@@ -49,8 +56,8 @@ public class IndexDocTests {
@Test
public void repositoryDemo() {
RepositoryDemo<ExpiringSession> demo = new RepositoryDemo<>();
demo.repository = new MapSessionRepository();
RepositoryDemo<MapSession> demo = new RepositoryDemo<>();
demo.repository = new MapSessionRepository(new ConcurrentHashMap<>());
demo.demo();
}
@@ -68,7 +75,7 @@ public class IndexDocTests {
this.repository.save(toSave); // <4>
S session = this.repository.getSession(toSave.getId()); // <5>
S session = this.repository.findById(toSave.getId()); // <5>
// <6>
User user = session.getAttribute(ATTR_USER);
@@ -81,24 +88,24 @@ public class IndexDocTests {
@Test
public void expireRepositoryDemo() {
ExpiringRepositoryDemo<ExpiringSession> demo = new ExpiringRepositoryDemo<>();
demo.repository = new MapSessionRepository();
ExpiringRepositoryDemo<MapSession> demo = new ExpiringRepositoryDemo<>();
demo.repository = new MapSessionRepository(new ConcurrentHashMap<>());
demo.demo();
}
// tag::expire-repository-demo[]
public class ExpiringRepositoryDemo<S extends ExpiringSession> {
public class ExpiringRepositoryDemo<S extends Session> {
private SessionRepository<S> repository; // <1>
public void demo() {
S toSave = this.repository.createSession(); // <2>
// ...
toSave.setMaxInactiveIntervalInSeconds(30); // <3>
toSave.setMaxInactiveInterval(Duration.ofSeconds(30)); // <3>
this.repository.save(toSave); // <4>
S session = this.repository.getSession(toSave.getId()); // <5>
S session = this.repository.findById(toSave.getId()); // <5>
// ...
}
@@ -110,17 +117,41 @@ public class IndexDocTests {
@SuppressWarnings("unused")
public void newRedisOperationsSessionRepository() {
// tag::new-redisoperationssessionrepository[]
LettuceConnectionFactory factory = new LettuceConnectionFactory();
SessionRepository<? extends ExpiringSession> repository = new RedisOperationsSessionRepository(
factory);
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
// ... configure redisTemplate ...
SessionRepository<? extends Session> repository =
new RedisOperationsSessionRepository(redisTemplate);
// end::new-redisoperationssessionrepository[]
}
@Test
@SuppressWarnings("unused")
public void newReactiveRedisOperationsSessionRepository() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
RedisSerializationContext<String, Object> serializationContext = RedisSerializationContext
.<String, Object>newSerializationContext(
new JdkSerializationRedisSerializer())
.build();
// tag::new-reactiveredisoperationssessionrepository[]
// ... create and configure connectionFactory and serializationContext ...
ReactiveRedisTemplate<String, Object> redisTemplate = new ReactiveRedisTemplate<>(
connectionFactory, serializationContext);
ReactiveSessionRepository<? extends Session> repository =
new ReactiveRedisOperationsSessionRepository(redisTemplate);
// end::new-reactiveredisoperationssessionrepository[]
}
@Test
@SuppressWarnings("unused")
public void mapRepository() {
// tag::new-mapsessionrepository[]
SessionRepository<? extends ExpiringSession> repository = new MapSessionRepository();
SessionRepository<? extends Session> repository = new MapSessionRepository(
new ConcurrentHashMap<>());
// end::new-mapsessionrepository[]
}
@@ -136,7 +167,7 @@ public class IndexDocTests {
// ... configure transactionManager ...
SessionRepository<? extends ExpiringSession> repository =
SessionRepository<? extends Session> repository =
new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
// end::new-jdbcoperationssessionrepository[]
}
@@ -152,11 +183,8 @@ public class IndexDocTests {
HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(config);
IMap<String, MapSession> sessions = hazelcastInstance
.getMap("spring:session:sessions");
HazelcastSessionRepository repository =
new HazelcastSessionRepository(sessions);
new HazelcastSessionRepository(hazelcastInstance);
// end::new-hazelcastsessionrepository[]
}

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,
@@ -25,7 +25,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.mockito.Mockito.mock;
@@ -33,7 +33,7 @@ import static org.mockito.Mockito.mock;
/**
* @author Rob Winch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(SpringRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class RedisHttpSessionConfigurationNoOpConfigureRedisActionTests {

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2017 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,
@@ -16,6 +16,8 @@
package docs;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.MapSessionRepository;
@@ -27,7 +29,7 @@ import org.springframework.session.config.annotation.web.http.EnableSpringHttpSe
public class SpringHttpSessionConfig {
@Bean
public MapSessionRepository sessionRepository() {
return new MapSessionRepository();
return new MapSessionRepository(new ConcurrentHashMap<>());
}
}
// end::class[]

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2018 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,
@@ -14,25 +14,21 @@
* limitations under the License.
*/
package sample;
package docs;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
/**
* @author Rob Winch
*/
import org.springframework.session.ReactiveMapSessionRepository;
import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.config.annotation.web.server.EnableSpringWebSession;
// tag::class[]
@Configuration
@EnableRedisHttpSession
public class Config {
@EnableSpringWebSession
public class SpringWebSessionConfig {
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory();
public ReactiveSessionRepository reactiveSessionRepository() {
return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
}
}
// end::class[]

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2017 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,
@@ -16,6 +16,8 @@
package docs.http;
import java.util.Properties;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -27,18 +29,20 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.core.session.SessionDestroyedEvent;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* @author Rob Winch
* @author Mark Paluch
* @since 1.2
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(SpringRunner.class)
@WebAppConfiguration
public abstract class AbstractHttpSessionListenerTests {
@Autowired
@@ -63,6 +67,7 @@ public abstract class AbstractHttpSessionListenerTests {
RedisConnection connection = mock(RedisConnection.class);
given(factory.getConnection()).willReturn(connection);
given(connection.getConfig(anyString())).willReturn(new Properties());
return factory;
}
@@ -77,6 +82,7 @@ public abstract class AbstractHttpSessionListenerTests {
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.
* springframework.context.ApplicationEvent)
*/
@Override
public void onApplicationEvent(SessionDestroyedEvent event) {
this.event = event;
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2017 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,
@@ -41,7 +41,7 @@ public class HazelcastHttpSessionConfig {
Config config = new Config();
config.getMapConfig("spring:session:sessions") // <2>
config.getMapConfig(HazelcastSessionRepository.DEFAULT_SESSION_MAP_NAME) // <2>
.addMapAttributeConfig(attributeConfig)
.addMapIndexConfig(new MapIndexConfig(
HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false));

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,11 +1,11 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2018 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,
@@ -16,13 +16,14 @@
package docs.security;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
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;
@@ -52,7 +53,7 @@ public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapte
// tag::rememberme-bean[]
@Bean
RememberMeServices rememberMeServices() {
public SpringSessionRememberMeServices rememberMeServices() {
SpringSessionRememberMeServices rememberMeServices =
new SpringSessionRememberMeServices();
// optionally customize
@@ -65,15 +66,13 @@ public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapte
@Override
@Bean
public InMemoryUserDetailsManager userDetailsService() {
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager();
uds.createUser(
User.withUsername("user").password("password").roles("USER").build());
return uds;
return new InMemoryUserDetailsManager(User.withUsername("user")
.password("{noop}password").roles("USER").build());
}
@Bean
MapSessionRepository sessionRepository() {
return new MapSessionRepository();
return new MapSessionRepository(new ConcurrentHashMap<>());
}
}
// end::class[]

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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,
@@ -16,8 +16,8 @@
package docs.security;
import java.time.Duration;
import java.util.Base64;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.Cookie;
@@ -26,11 +26,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.session.ExpiringSession;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
@@ -43,12 +43,13 @@ import static org.springframework.security.test.web.servlet.setup.SecurityMockMv
/**
* @author rwinch
* @author Vedran Pavic
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = RememberMeSecurityConfiguration.class)
@WebAppConfiguration
@SuppressWarnings("rawtypes")
public class RememberMeSecurityConfigurationTests<T extends ExpiringSession> {
public class RememberMeSecurityConfigurationTests<T extends Session> {
@Autowired
WebApplicationContext context;
@Autowired
@@ -81,10 +82,11 @@ public class RememberMeSecurityConfigurationTests<T extends ExpiringSession> {
Cookie cookie = result.getResponse().getCookie("SESSION");
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
T session = this.sessions
.getSession(new String(Base64.getDecoder().decode(cookie.getValue())));
assertThat(session.getMaxInactiveIntervalInSeconds())
.isEqualTo((int) TimeUnit.DAYS.toSeconds(30));
.findById(new String(Base64.getDecoder().decode(cookie.getValue())));
assertThat(session.getMaxInactiveInterval())
.isEqualTo(Duration.ofDays(30));
}
}
// end::class[]

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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,
@@ -16,8 +16,8 @@
package docs.security;
import java.time.Duration;
import java.util.Base64;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.Cookie;
@@ -26,11 +26,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.session.ExpiringSession;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
@@ -43,12 +43,13 @@ import static org.springframework.security.test.web.servlet.setup.SecurityMockMv
/**
* @author rwinch
* @author Vedran Pavic
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(SpringRunner.class)
@ContextConfiguration
@WebAppConfiguration
@SuppressWarnings("rawtypes")
public class RememberMeSecurityConfigurationXmlTests<T extends ExpiringSession> {
public class RememberMeSecurityConfigurationXmlTests<T extends Session> {
@Autowired
WebApplicationContext context;
@Autowired
@@ -81,10 +82,11 @@ public class RememberMeSecurityConfigurationXmlTests<T extends ExpiringSession>
Cookie cookie = result.getResponse().getCookie("SESSION");
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
T session = this.sessions
.getSession(new String(Base64.getDecoder().decode(cookie.getValue())));
assertThat(session.getMaxInactiveIntervalInSeconds())
.isEqualTo((int) TimeUnit.DAYS.toSeconds(30));
.findById(new String(Base64.getDecoder().decode(cookie.getValue())));
assertThat(session.getMaxInactiveInterval())
.isEqualTo(Duration.ofDays(30));
}
}
// end::class[]

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,
@@ -21,8 +21,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.session.ExpiringSession;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
/**
@@ -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<ExpiringSession> sessionRepository;
private FindByIndexNameSessionRepository<S> sessionRepository;
@Override
protected void configure(HttpSecurity http) throws Exception {
@@ -47,9 +48,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
}
@Bean
SpringSessionBackedSessionRegistry sessionRegistry() {
return new SpringSessionBackedSessionRegistry<ExpiringSession>(
this.sessionRepository);
public SpringSessionBackedSessionRegistry<S> sessionRegistry() {
return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
}
}
// end::class[]

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2018 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,
@@ -19,9 +19,9 @@ package docs.websocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* @author Rob Winch
@@ -30,8 +30,9 @@ import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/messages").withSockJS();
}

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>
@@ -20,9 +20,13 @@
<security:user-service>
<security:user name="user" password="password" authorities="ROLE_USER"/>
<security:user name="user" password="{noop}password" authorities="ROLE_USER"/>
</security:user-service>
<bean class="org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration"/>
<bean id="springSessionRepository" class="org.springframework.session.MapSessionRepository"/>
<bean id="springSessionRepository" class="org.springframework.session.MapSessionRepository">
<constructor-arg>
<bean class="java.util.concurrent.ConcurrentHashMap"/>
</constructor-arg>
</bean>
</beans>

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

@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!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="${config_loc}/suppressions.xml"/>
</module>
<!-- Root Checks -->
<module name="io.spring.javaformat.checkstyle.SpringChecks"/>
</module>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<!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="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.0.0.M1
version=2.0.0.M2
version=2.2.0.M1

View File

@@ -1,36 +1,33 @@
dependencyManagement {
imports {
mavenBom 'org.springframework:spring-framework-bom:5.0.0.RC2'
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-M4'
mavenBom 'org.springframework.security:spring-security-bom:5.0.0.M2'
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.6'
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 {
dependency 'com.fasterxml.jackson.core:jackson-databind:2.9.0.pr3'
dependency 'com.h2database:h2:1.4.195'
dependency 'com.hazelcast:hazelcast-client:3.8'
dependency 'com.hazelcast:hazelcast:3.8'
dependency 'com.maxmind.geoip2:geoip2:2.3.1'
dependency 'commons-codec:commons-codec:1.10'
dependencySet(group: 'com.hazelcast', version: '3.12') {
entry 'hazelcast'
entry 'hazelcast-client'
}
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.0.0.M2'
dependency 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1'
dependency 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.2-b02'
dependency 'javax.servlet:javax.servlet-api:3.1.0'
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 'org.apache.derby:derby:10.13.1.1'
dependency 'org.apache.httpcomponents:httpclient:4.5.3'
dependency 'org.apache.taglibs:taglibs-standard-jstlel:1.2.5'
dependency 'org.assertj:assertj-core:3.6.2'
dependency 'org.hsqldb:hsqldb:2.4.0'
dependency 'org.mockito:mockito-core:2.7.22'
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.26'
dependency 'org.webjars:bootstrap:2.3.2'
dependency 'org.webjars:html5shiv:3.7.3'
dependency 'org.webjars:jquery:1.9.0'
dependency 'org.webjars:knockout:2.3.0'
dependency 'org.webjars:sockjs-client:0.3.4'
dependency 'org.webjars:stomp-websocket:2.3.0'
dependency 'org.webjars:webjars-taglib:0.3'
dependency 'redis.clients:jedis:2.9.0'
dependency 'mysql:mysql-connector-java:8.0.15'
dependency 'org.apache.derby:derby:10.14.2.0'
dependency 'org.assertj:assertj-core:3.12.2'
dependency 'org.hsqldb:hsqldb:2.4.1'
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,6 +1,5 @@
#Wed Jan 11 10:54:44 CST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip

41
gradlew vendored
View File

@@ -1,4 +1,20 @@
#!/usr/bin/env bash
#!/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.
#
##############################################################################
##
@@ -28,16 +44,16 @@ 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"
warn ( ) {
warn () {
echo "$*"
}
die ( ) {
die () {
echo
echo "$*"
echo
@@ -154,16 +170,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
exec "$JAVACMD" "$@"

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,4 +0,0 @@
Demonstrates using Spring Session to lookup a user's session by the username.
The sample provides a hook to add the current username to the session (required for finding the user) by providing a custom implementation of Spring Security's `AuthenticationSuccessHandler`.
NOTE: This product includes GeoLite2 data created by MaxMind, available from http://www.maxmind.com

View File

@@ -5,11 +5,12 @@ dependencies {
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
compile "org.springframework.boot:spring-boot-starter-security"
compile "org.springframework.boot:spring-boot-starter-data-redis"
compile "org.springframework.boot:spring-boot-devtools"
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator"
compile "org.webjars:webjars-locator-core"
compile "com.maxmind.geoip2:geoip2"
compile "org.apache.httpcomponents:httpclient"
@@ -17,16 +18,5 @@ dependencies {
testCompile "org.assertj:assertj-core"
integrationTestCompile seleniumDependencies
}
integrationTest {
doFirst {
systemProperties['spring.session.redis.namespace'] = project.name
}
}
integrationTest {
doFirst {
systemProperties['spring.session.redis.namespace'] = project.name
}
integrationTestCompile "org.testcontainers:testcontainers"
}

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,
@@ -21,6 +21,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import org.testcontainers.containers.GenericContainer;
import sample.pages.HomePage;
import sample.pages.LoginPage;
@@ -28,6 +29,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
@@ -35,12 +39,15 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
/**
* @author Eddú Meléndez
* @author Rob Winch
* @author Vedran Pavic
*/
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class FindByUsernameTests {
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Autowired
private MockMvc mockMvc;
@@ -72,4 +79,23 @@ public class FindByUsernameTests {
home.terminateButtonDisabled();
}
@TestConfiguration
static class Config {
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
}
}

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

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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,
@@ -16,27 +16,34 @@
package sample.config;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* Spring Security configuration.
*
* @author Rob Winch
* @author Vedran Pavic
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
// tag::config[]
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated();
.permitAll();
}
// end::config[]
// @formatter:on
}

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-2016 the original author or authors.
* Copyright 2014-2018 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,
@@ -21,8 +21,8 @@ import java.util.Collection;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.session.ExpiringSession;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
@@ -39,15 +39,12 @@ import org.springframework.web.bind.annotation.RequestMethod;
public class IndexController {
// tag::findbyusername[]
@Autowired
FindByIndexNameSessionRepository<? extends ExpiringSession> sessions;
FindByIndexNameSessionRepository<? extends Session> sessions;
@RequestMapping("/")
public String index(Principal principal, Model model) {
Collection<? extends ExpiringSession> usersSessions = this.sessions
.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
principal.getName())
.values();
Collection<? extends Session> usersSessions = this.sessions
.findByPrincipalName(principal.getName()).values();
model.addAttribute("sessions", usersSessions);
return "index";
}
@@ -56,11 +53,10 @@ public class IndexController {
@RequestMapping(value = "/sessions/{sessionIdToDelete}", method = RequestMethod.DELETE)
public String removeSession(Principal principal,
@PathVariable String sessionIdToDelete) {
Set<String> usersSessionIds = this.sessions.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
principal.getName()).keySet();
Set<String> usersSessionIds = this.sessions
.findByPrincipalName(principal.getName()).keySet();
if (usersSessionIds.contains(sessionIdToDelete)) {
this.sessions.delete(sessionIdToDelete);
this.sessions.deleteById(sessionIdToDelete);
}
return "redirect:/";

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-2016 the original author or authors.
* Copyright 2014-2018 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,
@@ -57,6 +57,7 @@ public class SessionDetailsFilter extends OncePerRequestFilter {
}
// tag::dofilterinternal[]
@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
@@ -91,7 +92,7 @@ public class SessionDetailsFilter extends OncePerRequestFilter {
}
return cityName + ", " + countryName;
}
catch (Exception e) {
catch (Exception ex) {
return UNKNOWN;
}

View File

@@ -1,2 +1 @@
spring.session.store-type=redis
security.user.password=password
spring.security.user.password=password

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>
@@ -21,8 +21,8 @@
<tr th:each="sessionElement : ${sessions}" th:with="details=${sessionElement.getAttribute('SESSION_DETAILS')}">
<td th:text="${sessionElement.id.substring(30)}"></td>
<td th:text="${details?.location}"></td>
<td th:text="${#dates.format(new java.util.Date(sessionElement.creationTime),'dd/MMM/yyyy HH:mm:ss')}"></td>
<td th:text="${#dates.format(new java.util.Date(sessionElement.lastAccessedTime),'dd/MMM/yyyy HH:mm:ss')}"></td>
<td th:text="${#temporals.format(sessionElement.creationTime.atZone(T(java.time.ZoneId).systemDefault()),'dd/MMM/yyyy HH:mm:ss')}"></td>
<td th:text="${#temporals.format(sessionElement.lastAccessedTime.atZone(T(java.time.ZoneId).systemDefault()),'dd/MMM/yyyy HH:mm:ss')}"></td>
<td th:text="${details?.accessType}"></td>
<td>
<form th:action="@{'/sessions/' + ${sessionElement.id}}" th:method="delete">

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,
@@ -20,12 +20,11 @@ import com.maxmind.geoip2.DatabaseReader;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import sample.config.GeoConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
@@ -33,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Rob Winch
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = GeoConfig.class)
public class SessionDetailsFilterTests {
@Autowired

View File

@@ -1 +0,0 @@
Demonstrates using Spring Session with Spring Boot and Spring Security. You can log in with the username "user" and the password "password".

View File

@@ -9,7 +9,7 @@ dependencies {
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator"
compile "org.webjars:webjars-locator-core"
compile "com.h2database:h2"
testCompile "org.springframework.boot:spring-boot-starter-test"

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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,
@@ -34,6 +34,7 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
/**
* @author Eddú Meléndez
* @author Vedran Pavic
*/
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc

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-2018 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,
@@ -36,7 +36,7 @@ public class LoginPage extends BasePage {
}
public void assertAt() {
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
assertThat(getDriver().getTitle()).isEqualTo("Please sign in");
}
public Form form() {
@@ -51,7 +51,7 @@ public class LoginPage extends BasePage {
@FindBy(name = "password")
private WebElement password;
@FindBy(name = "submit")
@FindBy(tagName = "button")
private WebElement button;
public Form(SearchContext context) {

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-2018 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,
@@ -16,11 +16,15 @@
package sample.config;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* Spring Security configuration.
*
* @author Rob Winch
* @author Vedran Pavic
*/
@@ -29,10 +33,25 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
@Override
public void configure(WebSecurity web) throws Exception {
public void configure(WebSecurity web) {
web
.ignoring().antMatchers("/h2-console/**");
.ignoring().requestMatchers(PathRequest.toH2Console());
}
// @formatter:on
// @formatter:off
// tag::config[]
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
}
// end::config[]
// @formatter:on
}

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,3 +1,2 @@
spring.session.store-type=jdbc
security.user.password=password
spring.security.user.password=password
spring.h2.console.enabled=true

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,18 +1,16 @@
apply plugin: 'io.spring.convention.spring-sample-boot'
dependencies {
compile(project(':spring-session-data-redis')) {
exclude module: 'jedis'
}
compile project(':spring-session-data-redis')
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
compile "org.springframework.boot:spring-boot-starter-security"
compile "org.springframework.boot:spring-boot-starter-data-redis"
compile "org.springframework.boot:spring-boot-devtools"
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator"
compile "io.lettuce:lettuce-core"
compile "org.webjars:webjars-locator-core"
compile "org.apache.httpcomponents:httpclient"
testCompile "org.springframework.boot:spring-boot-starter-test"
@@ -20,4 +18,5 @@ dependencies {
testCompile "org.skyscreamer:jsonassert"
integrationTestCompile seleniumDependencies
integrationTestCompile "org.testcontainers:testcontainers"
}

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,
@@ -23,6 +23,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import org.testcontainers.containers.GenericContainer;
import sample.pages.HomePage;
import sample.pages.HomePage.Attribute;
import sample.pages.LoginPage;
@@ -31,6 +32,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
@@ -39,12 +43,15 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Vedran Pavic
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class HttpRedisJsonTest {
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Autowired
private MockMvc mockMvc;
@@ -96,4 +103,23 @@ public class HttpRedisJsonTest {
assertThat(attributes).extracting("attributeValue").contains("Demo Value");
}
@TestConfiguration
static class Config {
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2016 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,
@@ -13,28 +13,36 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.testcontainers.containers.GenericContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisOperations;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author jitendra on 8/3/16.
* @author jitendra
* @author Vedran Pavic
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisSerializerTest {
@Autowired
RedisTemplate<Object, Object> sessionRedisTemplate;
private static final String DOCKER_IMAGE = "redis:5.0.4";
@SpringSessionRedisOperations
private RedisTemplate<Object, Object> sessionRedisTemplate;
@Test
public void testRedisTemplate() {
@@ -43,4 +51,24 @@ public class RedisSerializerTest {
assertThat(this.sessionRedisTemplate.getDefaultSerializer())
.isInstanceOf(GenericJackson2JsonRedisSerializer.class);
}
@TestConfiguration
static class Config {
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
}
}

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,

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