Compare commits
637 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bdb3f6ded | ||
|
|
7d3472f55d | ||
|
|
00465a6f00 | ||
|
|
ad35d7ca30 | ||
|
|
18e9ab4c0f | ||
|
|
1c9a6d3e5d | ||
|
|
d2936ed0b4 | ||
|
|
cdf6089ccd | ||
|
|
1ca8a6476a | ||
|
|
cf926045dc | ||
|
|
7123df8656 | ||
|
|
096a5683cb | ||
|
|
db31527c8c | ||
|
|
3d2a742328 | ||
|
|
7ac6e458e0 | ||
|
|
9adf0a6e0c | ||
|
|
58219fa016 | ||
|
|
83cbff5ce2 | ||
|
|
936fc853df | ||
|
|
dba475c48f | ||
|
|
9956e91b93 | ||
|
|
c902981eba | ||
|
|
2e26c6e9d3 | ||
|
|
b9cd3865c5 | ||
|
|
1f7232f12e | ||
|
|
03f0a571b6 | ||
|
|
63a215f73b | ||
|
|
8dac35cf73 | ||
|
|
19b8583d65 | ||
|
|
6de0f44241 | ||
|
|
60d6120b9c | ||
|
|
3bc899e695 | ||
|
|
c2fe999d6c | ||
|
|
d214971e72 | ||
|
|
f4704293a1 | ||
|
|
a8c4f65903 | ||
|
|
4a52de0c18 | ||
|
|
63f105082a | ||
|
|
f55b793185 | ||
|
|
6d027900ee | ||
|
|
42818a1b90 | ||
|
|
b6348736ac | ||
|
|
60581c6427 | ||
|
|
836ea12e93 | ||
|
|
670148f182 | ||
|
|
a39295c02b | ||
|
|
02cd5a6301 | ||
|
|
5824566621 | ||
|
|
b2711600e2 | ||
|
|
06eb768721 | ||
|
|
fb05fa70c7 | ||
|
|
1e93fe87db | ||
|
|
e67f84c6b6 | ||
|
|
dfb2f2f334 | ||
|
|
c8e9630fdd | ||
|
|
751375338c | ||
|
|
538712d162 | ||
|
|
941fdb46f2 | ||
|
|
bb1c099094 | ||
|
|
1d1253e643 | ||
|
|
0e7e2eaf5c | ||
|
|
e601e03e1e | ||
|
|
2c81e50b5e | ||
|
|
ac5ff996f4 | ||
|
|
44130cba80 | ||
|
|
2cd8063c7c | ||
|
|
f42a6c7d1c | ||
|
|
6c2f6c26cc | ||
|
|
91b4efc5bd | ||
|
|
6f8359ba16 | ||
|
|
62bfeb3f05 | ||
|
|
2395582fe6 | ||
|
|
5173026aa8 | ||
|
|
d97ad2ca3e | ||
|
|
a780ee0264 | ||
|
|
d8e7a2aa9f | ||
|
|
45b18dec84 | ||
|
|
ec5406fb01 | ||
|
|
3c2f0fd485 | ||
|
|
cdfa557442 | ||
|
|
edc8a7efff | ||
|
|
a7a30dad30 | ||
|
|
be1d3d30a8 | ||
|
|
010aa5f013 | ||
|
|
bfcb4afef7 | ||
|
|
72a902009e | ||
|
|
1e799f211f | ||
|
|
90599b9bd3 | ||
|
|
8d7136072a | ||
|
|
4f0f3806a2 | ||
|
|
a18037759c | ||
|
|
eb479af1d4 | ||
|
|
d0b472e8e2 | ||
|
|
17ee9d51f2 | ||
|
|
003996a1b3 | ||
|
|
13c0e325b4 | ||
|
|
7acdeffe22 | ||
|
|
de03b20619 | ||
|
|
becee53dbf | ||
|
|
4eb64e8140 | ||
|
|
e520ea237d | ||
|
|
175e05dcda | ||
|
|
bb427ff1af | ||
|
|
0a65b82373 | ||
|
|
e25c64efae | ||
|
|
43fcba65c4 | ||
|
|
1cc2c83f36 | ||
|
|
0941358807 | ||
|
|
7d3698515e | ||
|
|
d382603445 | ||
|
|
22e3b5ce38 | ||
|
|
ebd4b349d2 | ||
|
|
ffa1bca898 | ||
|
|
d0ee9fd16a | ||
|
|
7a631fe414 | ||
|
|
d217077dec | ||
|
|
a9b3ce034b | ||
|
|
1ba434a357 | ||
|
|
45807998f6 | ||
|
|
2f49a8ac25 | ||
|
|
e364511c7e | ||
|
|
79ccbe7066 | ||
|
|
1edce117aa | ||
|
|
c0f4c7f381 | ||
|
|
7fa07b2973 | ||
|
|
3252b38c87 | ||
|
|
c4daeff3d8 | ||
|
|
2fccca1158 | ||
|
|
81798c36f6 | ||
|
|
27283e29d5 | ||
|
|
77bb9dfdb1 | ||
|
|
c874592323 | ||
|
|
676f0e474e | ||
|
|
e5ec612771 | ||
|
|
280d5c5a77 | ||
|
|
6a370b1ef8 | ||
|
|
41de1b087a | ||
|
|
6188fe68b7 | ||
|
|
ed328ff4b1 | ||
|
|
97ad0311e2 | ||
|
|
702bc37a99 | ||
|
|
17e56dda18 | ||
|
|
f5912da089 | ||
|
|
bff8ce3c03 | ||
|
|
a3803e9e1f | ||
|
|
3fcdc9ebce | ||
|
|
36d157a658 | ||
|
|
f28ab07b9a | ||
|
|
42a6001aae | ||
|
|
fc4d2238bc | ||
|
|
36d349f328 | ||
|
|
5f23a41674 | ||
|
|
4c9fbd5b6b | ||
|
|
f2ba773ec2 | ||
|
|
647dd7c7bb | ||
|
|
555223755d | ||
|
|
2e65d89ecc | ||
|
|
f3f18432ee | ||
|
|
03f6611e04 | ||
|
|
fff1d83097 | ||
|
|
91d4a5bfca | ||
|
|
34f29cf36c | ||
|
|
7e26897ec2 | ||
|
|
9ea1fb9af1 | ||
|
|
2c664d1d9e | ||
|
|
97698fd590 | ||
|
|
fe3f40c6f4 | ||
|
|
f8583bb02f | ||
|
|
5df555cd53 | ||
|
|
6f05c84aa7 | ||
|
|
cd394bbe10 | ||
|
|
2ecb2e60c0 | ||
|
|
d04a95ebfb | ||
|
|
858b52235e | ||
|
|
00ede81665 | ||
|
|
6cfa975b29 | ||
|
|
8b9d421ad6 | ||
|
|
df7ab9d99e | ||
|
|
7d61c5496a | ||
|
|
3492bc01d2 | ||
|
|
e08ac357dd | ||
|
|
1c29c7f14f | ||
|
|
33fbaa03a8 | ||
|
|
88b26f2cfe | ||
|
|
3f670050ef | ||
|
|
e3b61d25bb | ||
|
|
19b8effa41 | ||
|
|
9f5f7540d2 | ||
|
|
eb8c22939c | ||
|
|
45cfa1e9a4 | ||
|
|
99221e0948 | ||
|
|
41cf2ef152 | ||
|
|
c51bce4777 | ||
|
|
b6f1184c4c | ||
|
|
c69a8b8762 | ||
|
|
99fb17a66b | ||
|
|
937b2fcbf1 | ||
|
|
9c5a7e9156 | ||
|
|
4deccd3ad0 | ||
|
|
da058e9510 | ||
|
|
d28ca4658b | ||
|
|
c14fdb283d | ||
|
|
ee1ff3ed3b | ||
|
|
eb7bcc5eeb | ||
|
|
188e5ba4e0 | ||
|
|
1e46630467 | ||
|
|
b72c600884 | ||
|
|
274aec1691 | ||
|
|
52ea98b4ce | ||
|
|
5c294ae1d2 | ||
|
|
1752928d96 | ||
|
|
0cdee25405 | ||
|
|
4a9f1700d5 | ||
|
|
36ab358d24 | ||
|
|
8e3371aed9 | ||
|
|
2161f966de | ||
|
|
63b67a501d | ||
|
|
2b0431eae4 | ||
|
|
04ec086014 | ||
|
|
5697f49a71 | ||
|
|
dfce66383f | ||
|
|
a83e59bf52 | ||
|
|
8b233e84ef | ||
|
|
84e7fbace1 | ||
|
|
f455df3333 | ||
|
|
a7bb9d3b31 | ||
|
|
5f0e4c3b85 | ||
|
|
23c6c7cf31 | ||
|
|
c8c5fae678 | ||
|
|
f4a58622e4 | ||
|
|
5384764021 | ||
|
|
56033a9b68 | ||
|
|
99a2b079ac | ||
|
|
9120151692 | ||
|
|
5abbe66b1d | ||
|
|
f00c196430 | ||
|
|
be2604ca69 | ||
|
|
2aa71ffb6d | ||
|
|
8bdcba6e50 | ||
|
|
8dd1a10f1b | ||
|
|
1d247aa96f | ||
|
|
c00d6a7bf2 | ||
|
|
c0df3bf28b | ||
|
|
1b8c9838a4 | ||
|
|
8a1b454121 | ||
|
|
ef69c8169a | ||
|
|
40b3d07224 | ||
|
|
8c726f2215 | ||
|
|
c2a86a27ce | ||
|
|
6a08ef6f97 | ||
|
|
9c4e20f074 | ||
|
|
5845a9c46a | ||
|
|
7c6693a268 | ||
|
|
05a3f59813 | ||
|
|
47a7a35aa4 | ||
|
|
04b4fe3e3b | ||
|
|
36bb65e4b5 | ||
|
|
8ef36e4f3e | ||
|
|
ab3e280993 | ||
|
|
30562b5749 | ||
|
|
d42a7b65ea | ||
|
|
db9807d12b | ||
|
|
db09fa8168 | ||
|
|
031541bc05 | ||
|
|
084e3428fb | ||
|
|
b321ff02f0 | ||
|
|
c6c6beb40c | ||
|
|
0127ef9f9b | ||
|
|
cd8686ae9c | ||
|
|
233d179bfa | ||
|
|
4e8ae8d9d4 | ||
|
|
8c6810c6dd | ||
|
|
fca411996a | ||
|
|
79b8296e1c | ||
|
|
043cb42149 | ||
|
|
c28f047eb5 | ||
|
|
972cf66d7e | ||
|
|
f1319483ee | ||
|
|
6ad5006280 | ||
|
|
f7e07b7f6b | ||
|
|
4cf26d9c36 | ||
|
|
a848df1235 | ||
|
|
f8292ba512 | ||
|
|
21bcc6e8d7 | ||
|
|
905a77a3a8 | ||
|
|
295f9f78c3 | ||
|
|
04ecc82d09 | ||
|
|
2ddd9e58a3 | ||
|
|
3c52298c47 | ||
|
|
7b385c7d33 | ||
|
|
87d51c54c9 | ||
|
|
210e8eebc5 | ||
|
|
7d52c87173 | ||
|
|
e3c6fb67f2 | ||
|
|
79f187ddd6 | ||
|
|
22f4b0bc9d | ||
|
|
c5ea626d03 | ||
|
|
d067cd1e66 | ||
|
|
76a6be572a | ||
|
|
78db900303 | ||
|
|
7f9a9c4185 | ||
|
|
83c67d3e11 | ||
|
|
4f3324bac4 | ||
|
|
23a28f790a | ||
|
|
dd4983f33e | ||
|
|
e9e5d8eda6 | ||
|
|
a745d471ad | ||
|
|
df267774da | ||
|
|
2b2f385d5f | ||
|
|
86e892c806 | ||
|
|
448133494f | ||
|
|
e0fc9e92ba | ||
|
|
5b4d0c40d8 | ||
|
|
78ea101a43 | ||
|
|
63097e9d82 | ||
|
|
2ebbe762f0 | ||
|
|
63b836b212 | ||
|
|
02da23a2a0 | ||
|
|
b254c7c6b9 | ||
|
|
89adc13201 | ||
|
|
e6e752aea5 | ||
|
|
d590ca58e4 | ||
|
|
e23aaeca5f | ||
|
|
0312c31a42 | ||
|
|
815cbf4ee8 | ||
|
|
6327d36ce9 | ||
|
|
707b8bb062 | ||
|
|
adbff45a23 | ||
|
|
f30cb7a1e6 | ||
|
|
432eb84a94 | ||
|
|
bd31710117 | ||
|
|
e67afefcd8 | ||
|
|
327323da38 | ||
|
|
83e5d6f2a7 | ||
|
|
887f024551 | ||
|
|
8dd6aa38ed | ||
|
|
6f4025eacb | ||
|
|
3cc53fae2c | ||
|
|
25ded686ac | ||
|
|
9b30726805 | ||
|
|
aeb182712c | ||
|
|
18ccee051f | ||
|
|
3f239b4956 | ||
|
|
dc3b6ba6f1 | ||
|
|
ddf9ef66c1 | ||
|
|
b65423f296 | ||
|
|
b3706addbb | ||
|
|
5c6565bd9c | ||
|
|
3e24393e9a | ||
|
|
0e10b7763c | ||
|
|
012f121c48 | ||
|
|
c0cc15679c | ||
|
|
43d83f6398 | ||
|
|
862659b9b7 | ||
|
|
536156a4ec | ||
|
|
aa3536a71a | ||
|
|
dd23c96c1a | ||
|
|
41fbc90ec2 | ||
|
|
3cc3784313 | ||
|
|
489cf01812 | ||
|
|
94fc80a8f0 | ||
|
|
3ad0028785 | ||
|
|
801f88d793 | ||
|
|
0d6b62b7a9 | ||
|
|
00d5d76833 | ||
|
|
85a1b43242 | ||
|
|
800d52279f | ||
|
|
61a6344ffa | ||
|
|
c182e90a1a | ||
|
|
7dc3e12e07 | ||
|
|
ce5e44233e | ||
|
|
22c416e32b | ||
|
|
ff72bf1234 | ||
|
|
a45199059b | ||
|
|
37045e337c | ||
|
|
41e3f91b75 | ||
|
|
efeed5e2cf | ||
|
|
1952a4550f | ||
|
|
9efb5b59e5 | ||
|
|
4b196744f2 | ||
|
|
8e7c736a0a | ||
|
|
1a318b89d9 | ||
|
|
f98697416e | ||
|
|
d66fa56513 | ||
|
|
89c91c19d8 | ||
|
|
5e294b805f | ||
|
|
a7b5f86bcd | ||
|
|
9c236fa256 | ||
|
|
304e32eef5 | ||
|
|
288c622012 | ||
|
|
3827ae1e72 | ||
|
|
9067f8235d | ||
|
|
19928e6b7f | ||
|
|
1df1a76069 | ||
|
|
17e397212d | ||
|
|
39503a21a7 | ||
|
|
ebbc10b2b4 | ||
|
|
9a51cb9ca7 | ||
|
|
5e0ee5077a | ||
|
|
526c6ee012 | ||
|
|
ff4045acbd | ||
|
|
2d359986d3 | ||
|
|
6424910c83 | ||
|
|
49e3a1c7cd | ||
|
|
3b8258f233 | ||
|
|
a2b30eb54b | ||
|
|
4c2581d432 | ||
|
|
25aec99357 | ||
|
|
1c9dfa6638 | ||
|
|
466e2cf102 | ||
|
|
eb0f292c20 | ||
|
|
43fda301e2 | ||
|
|
4a06b38c5f | ||
|
|
6a78101db5 | ||
|
|
b5ea6c752d | ||
|
|
46633274d5 | ||
|
|
038287b2cc | ||
|
|
32c053271c | ||
|
|
802e0e714b | ||
|
|
6263f6e927 | ||
|
|
5671037c39 | ||
|
|
3d44467275 | ||
|
|
94221c70a9 | ||
|
|
dd3a571494 | ||
|
|
e4fe53abf8 | ||
|
|
7b65d7930b | ||
|
|
0f8326516b | ||
|
|
2aec28289e | ||
|
|
af7a5a208f | ||
|
|
e9924d27a1 | ||
|
|
f0820c8038 | ||
|
|
7d680ff3ef | ||
|
|
6d9885455b | ||
|
|
06104c348d | ||
|
|
090742350c | ||
|
|
a290b11019 | ||
|
|
eabad84ba8 | ||
|
|
4e33b7740c | ||
|
|
f8967c4c13 | ||
|
|
245e634bea | ||
|
|
7a2914323f | ||
|
|
6e04d903ae | ||
|
|
d8c3a4dd61 | ||
|
|
997813088a | ||
|
|
5ecf390932 | ||
|
|
8167b43e63 | ||
|
|
1f7193f32d | ||
|
|
0e1d81f509 | ||
|
|
8b97a32db2 | ||
|
|
d3379029bb | ||
|
|
26eca5b448 | ||
|
|
6335894e13 | ||
|
|
34948d6451 | ||
|
|
bff0f8f845 | ||
|
|
2052ec8d44 | ||
|
|
cbd96999e0 | ||
|
|
61492c4ae1 | ||
|
|
97fef0f9bd | ||
|
|
2792d2a0e9 | ||
|
|
2724b333b3 | ||
|
|
8db7d394ba | ||
|
|
3e293e8b54 | ||
|
|
de7bb05fc1 | ||
|
|
3ee4c5b5d0 | ||
|
|
acf37fc8f4 | ||
|
|
1256a94d7e | ||
|
|
bbb94361f8 | ||
|
|
9af3f1fcec | ||
|
|
5b70d55a21 | ||
|
|
9133e337e6 | ||
|
|
9f36fd69ee | ||
|
|
e684f58403 | ||
|
|
508e3e90a7 | ||
|
|
0018a2f772 | ||
|
|
e9f097db5c | ||
|
|
7e41e40762 | ||
|
|
dc553104c6 | ||
|
|
2b4a349b1a | ||
|
|
4a1f132e07 | ||
|
|
940555653c | ||
|
|
82cb417910 | ||
|
|
808a550343 | ||
|
|
cc08f83ce0 | ||
|
|
53c81de5e3 | ||
|
|
dd268992a8 | ||
|
|
00004e2f50 | ||
|
|
afb9a11abf | ||
|
|
fb356f02ff | ||
|
|
509fb99a5d | ||
|
|
2aff5b0377 | ||
|
|
016a007d12 | ||
|
|
2a3ec2f4b9 | ||
|
|
458ac6e700 | ||
|
|
33321d2e53 | ||
|
|
20130f8e8a | ||
|
|
03f008f283 | ||
|
|
00e7110594 | ||
|
|
f973e63fce | ||
|
|
edbf8bf587 | ||
|
|
234f6c954a | ||
|
|
e0417523f6 | ||
|
|
5865b0a715 | ||
|
|
67201417df | ||
|
|
01a149737e | ||
|
|
2d6f505a30 | ||
|
|
7c616a1adf | ||
|
|
61b01d9ecd | ||
|
|
f9163d94fd | ||
|
|
3f819a94b1 | ||
|
|
1e1d24895c | ||
|
|
e134a4cdb8 | ||
|
|
75006cd7dd | ||
|
|
9c8f8894e1 | ||
|
|
99db45ea72 | ||
|
|
c07583bd47 | ||
|
|
cce8dac4b7 | ||
|
|
5bde226ecc | ||
|
|
f8f6ee20c0 | ||
|
|
3bb96e8e82 | ||
|
|
b7367680cb | ||
|
|
a26a21b663 | ||
|
|
3825a46418 | ||
|
|
779277b16d | ||
|
|
b97306a83d | ||
|
|
6b13111079 | ||
|
|
63006db45d | ||
|
|
0a99e065ff | ||
|
|
bd2d846917 | ||
|
|
79928bd7fe | ||
|
|
903cac492e | ||
|
|
3980be349b | ||
|
|
128e0c4d47 | ||
|
|
37bc6a352f | ||
|
|
b88f48f01d | ||
|
|
028e277fc9 | ||
|
|
904cdf4e65 | ||
|
|
b58ea03a3b | ||
|
|
9014ac9060 | ||
|
|
7a82915a98 | ||
|
|
e16224583c | ||
|
|
96861ea535 | ||
|
|
de3d04fb29 | ||
|
|
68823eec29 | ||
|
|
a58d4f64fb | ||
|
|
40ad82806c | ||
|
|
6db7d45f65 | ||
|
|
bbbdf939e8 | ||
|
|
e23398b890 | ||
|
|
5cfbeae161 | ||
|
|
c6e71a90bb | ||
|
|
195228ff5a | ||
|
|
831d2f4152 | ||
|
|
4f7728f5b5 | ||
|
|
11e418526e | ||
|
|
49f24e493d | ||
|
|
bd6d5bf419 | ||
|
|
9b989c4a3e | ||
|
|
68ddcef83e | ||
|
|
2592905b41 | ||
|
|
4be47f6b40 | ||
|
|
35b5fcdc75 | ||
|
|
4d010b23b8 | ||
|
|
f0200696ef | ||
|
|
7f3302253b | ||
|
|
9e3bcafa75 | ||
|
|
216bfd7355 | ||
|
|
34cebc3df6 | ||
|
|
7b28b214ff | ||
|
|
8f8cfe5d79 | ||
|
|
e0e29eab35 | ||
|
|
cd38e307e0 | ||
|
|
091d0d8d9f | ||
|
|
3300b58afe | ||
|
|
00af8456d4 | ||
|
|
aeb0add50e | ||
|
|
671bfa0444 | ||
|
|
8bf3a251bb | ||
|
|
5d1c60711f | ||
|
|
32cf8ad7ad | ||
|
|
d3139b04e1 | ||
|
|
cc0bfc2299 | ||
|
|
c0a5916413 | ||
|
|
11ca552625 | ||
|
|
8e4ed22974 | ||
|
|
53d7c84f73 | ||
|
|
1871915c62 | ||
|
|
d5259bf0e9 | ||
|
|
12b1dda24c | ||
|
|
fad66c5cd2 | ||
|
|
e338e70972 | ||
|
|
4c01782d6c | ||
|
|
5bf12fdd93 | ||
|
|
d209a10514 | ||
|
|
1d0eb68f70 | ||
|
|
b64d0c0d3c | ||
|
|
305ce1ae65 | ||
|
|
aed79ddbf7 | ||
|
|
3b5fc5e9cc | ||
|
|
e0bbbbcd45 | ||
|
|
5f23b3c272 | ||
|
|
bf7729b936 | ||
|
|
7c53558454 | ||
|
|
f2443f5e21 | ||
|
|
2b5386ad98 | ||
|
|
c2b407189e | ||
|
|
7de11753a9 | ||
|
|
2d6a474c2c | ||
|
|
cc1d3a7e9e | ||
|
|
fe17e3fcc0 | ||
|
|
ef904a4544 | ||
|
|
207e4e27b3 | ||
|
|
bda5c85acf | ||
|
|
c9acd3c812 | ||
|
|
f20acbf9b9 | ||
|
|
ad09b498a3 | ||
|
|
7618aafb90 | ||
|
|
7a3bf533b3 | ||
|
|
723ea5e2e0 | ||
|
|
7463592988 | ||
|
|
198acc0648 | ||
|
|
f53e991d02 | ||
|
|
22f6f9dd72 | ||
|
|
019e0083b0 | ||
|
|
1931da83a5 | ||
|
|
5dff0ff37b | ||
|
|
1003821dad | ||
|
|
5399b7c299 | ||
|
|
969053fa87 | ||
|
|
eb646ef5d8 | ||
|
|
f14942edb0 | ||
|
|
18a07abeb4 | ||
|
|
e766ad774d | ||
|
|
b38cc74764 | ||
|
|
3df40dd8a9 | ||
|
|
9d95638cf8 | ||
|
|
d85624c58e | ||
|
|
5ca6377015 |
19
.editorconfig
Normal 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
|
||||
7
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +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.
|
||||
-->
|
||||
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +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 #).
|
||||
-->
|
||||
3
.gitignore
vendored
@@ -10,3 +10,6 @@ target
|
||||
out
|
||||
.springBeans
|
||||
*.rdb
|
||||
.checkstyle
|
||||
!etc/eclipse/.checkstyle
|
||||
!**/src/**/build
|
||||
|
||||
20
.travis.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
language: java
|
||||
|
||||
sudo: required
|
||||
|
||||
services: docker
|
||||
|
||||
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/
|
||||
|
||||
install: true
|
||||
|
||||
script: ./gradlew clean build --refresh-dependencies --no-daemon
|
||||
44
CODE_OF_CONDUCT.adoc
Normal file
@@ -0,0 +1,44 @@
|
||||
= Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering an open
|
||||
and welcoming community, we pledge to respect all people who contribute through reporting
|
||||
issues, posting feature requests, updating documentation, submitting pull requests or
|
||||
patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for
|
||||
everyone, regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
|
||||
religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses,
|
||||
without explicit permission
|
||||
* Other unethical or unprofessional conduct
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments,
|
||||
commits, code, wiki edits, issues, and other contributions that are not aligned to this
|
||||
Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
|
||||
that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
By adopting this Code of Conduct, project maintainers commit themselves to fairly and
|
||||
consistently applying these principles to every aspect of managing this project. Project
|
||||
maintainers who do not follow or enforce the Code of Conduct may be permanently removed
|
||||
from the project team.
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an
|
||||
individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
|
||||
contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will
|
||||
be reviewed and investigated and will result in a response that is deemed necessary and
|
||||
appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
|
||||
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/]
|
||||
@@ -3,7 +3,9 @@
|
||||
Spring Session is released under the Apache 2.0 license. If you would like to contribute
|
||||
something, or simply want to hack on the code this document should help you get started.
|
||||
|
||||
|
||||
== 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.
|
||||
|
||||
== Using GitHub issues
|
||||
|
||||
@@ -19,12 +21,6 @@ reproduces the problem.
|
||||
|
||||
|
||||
== Sign the Contributor License Agreement
|
||||
Before we accept a non-trivial patch or pull request we will need you to sign the
|
||||
https://support.springsource.com/spring_committer_signup[contributor's agreement].
|
||||
If you have previously signed the CLA for any project, there is no need to sign up again.
|
||||
Signing the contributor's agreement does not grant anyone commit rights to the main
|
||||
repository, but it does mean that we can accept your contributions, and you will get an
|
||||
author credit if we do. Active contributors might be asked to join the core team, and
|
||||
given the ability to merge pull requests. Use the project `Spring Security` (the parent project)
|
||||
and '`Rob Winch`' in the project lead field when you complete the form.
|
||||
If you have not previously done so, please fill out and
|
||||
submit the https://cla.pivotal.io/sign/spring[Contributor License Agreement].
|
||||
|
||||
|
||||
79
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
def projectProperties = [
|
||||
[$class: 'BuildDiscarderProperty',
|
||||
strategy: [$class: 'LogRotator', numToKeepStr: '5']],
|
||||
pipelineTriggers([cron('@daily')])
|
||||
]
|
||||
properties(projectProperties)
|
||||
|
||||
def SUCCESS = hudson.model.Result.SUCCESS.toString()
|
||||
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'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(currentBuild.result == 'SUCCESS') {
|
||||
parallel artifacts: {
|
||||
stage('Deploy Artifacts') {
|
||||
node {
|
||||
checkout scm
|
||||
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 -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 --refresh-dependencies --no-daemon --stacktrace"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
docs: {
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
def buildStatus = currentBuild.result
|
||||
def buildNotSuccess = !SUCCESS.equals(buildStatus)
|
||||
def lastBuildNotSuccess = !SUCCESS.equals(currentBuild.previousBuild?.result)
|
||||
|
||||
if(buildNotSuccess || lastBuildNotSuccess) {
|
||||
|
||||
stage('Notifiy') {
|
||||
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}"""
|
||||
|
||||
emailext (
|
||||
subject: subject,
|
||||
body: details,
|
||||
recipientProviders: RECIPIENTS,
|
||||
to: "$SPRING_SESSION_TEAM_EMAILS"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
202
LICENSE.txt
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://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
|
||||
|
||||
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.
|
||||
32
README.adoc
@@ -1,18 +1,32 @@
|
||||
= 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:
|
||||
|
||||
= Spring Session Project Site
|
||||
* `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
|
||||
|
||||
You can find the documentation, issue management, support, samples, and guides for using Spring Session at http://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].
|
||||
|
||||
60
build.gradle
@@ -1,66 +1,20 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url "https://repo.spring.io/plugins-release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:1.2.3")
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
|
||||
classpath("io.spring.gradle:spring-io-plugin:0.0.4.RELEASE")
|
||||
classpath('me.champeau.gradle:gradle-javadoc-hotfix-plugin:0.1')
|
||||
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2'
|
||||
classpath 'io.spring.gradle:spring-build-conventions:0.0.17.RELEASE'
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
|
||||
}
|
||||
repositories {
|
||||
maven { url 'https://repo.spring.io/plugins-release' }
|
||||
}
|
||||
}
|
||||
apply plugin: 'io.spring.convention.root'
|
||||
|
||||
group = 'org.springframework.session'
|
||||
description = 'Spring Session'
|
||||
|
||||
ext.springBootVersion = '1.2.3.RELEASE'
|
||||
ext.JAVA_GRADLE = "$rootDir/gradle/java.gradle"
|
||||
ext.SPRING3_GRADLE = "$rootDir/gradle/spring3.gradle"
|
||||
ext.MAVEN_GRADLE = "$rootDir/gradle/publish-maven.gradle"
|
||||
ext.TOMCAT_GRADLE = "$rootDir/gradle/tomcat.gradle"
|
||||
ext.TOMCAT_6_GRADLE = "$rootDir/gradle/tomcat6.gradle"
|
||||
ext.TOMCAT_7_GRADLE = "$rootDir/gradle/tomcat7.gradle"
|
||||
|
||||
ext.releaseBuild = version.endsWith('RELEASE')
|
||||
ext.snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
ext.milestoneBuild = !(releaseBuild || snapshotBuild)
|
||||
|
||||
apply plugin: 'sonar-runner'
|
||||
apply plugin: 'base'
|
||||
|
||||
|
||||
sonarRunner {
|
||||
sonarProperties {
|
||||
property "sonar.java.coveragePlugin", "jacoco"
|
||||
property "sonar.projectName", "Spring Session"
|
||||
property "sonar.jacoco.reportPath", "${buildDir.name}/jacoco.exec"
|
||||
property "sonar.links.homepage", 'https://github.com/spring-projects/spring-session'
|
||||
property "sonar.links.ci", 'https://build.spring.io/browse/SESSION'
|
||||
property "sonar.links.issue", 'https://github.com/spring-projects/spring-session/issues'
|
||||
property "sonar.links.scm", 'https://github.com/spring-projects/spring-session'
|
||||
property "sonar.links.scm_dev", 'https://github.com/spring-projects/spring-session.git'
|
||||
property "sonar.java.coveragePlugin", "jacoco"
|
||||
}
|
||||
}
|
||||
|
||||
task configDocsZip(dependsOn: [':docs:asciidoctor',':spring-session:javadoc']) << {
|
||||
project.tasks.docsZip.from(project(':docs').asciidoctor) {
|
||||
into('reference')
|
||||
}
|
||||
project.tasks.docsZip.from(project(':spring-session').javadoc) {
|
||||
into('api')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
task docsZip(type: Zip, dependsOn: 'configDocsZip') {
|
||||
group = "Distribution"
|
||||
baseName = "spring-session"
|
||||
classifier = "docs"
|
||||
description = "Builds -${classifier} archive containing api and reference " +
|
||||
"for deployment."
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives docsZip
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'org.kordamp.gradle:livereload-gradle-plugin:0.2.1'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'org.kordamp.gradle.livereload'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.asciidoctor.convert'
|
||||
|
||||
liveReload {
|
||||
docRoot asciidoctor.sourceDir.canonicalPath
|
||||
}
|
||||
|
||||
asciidoctorj {
|
||||
|
||||
}
|
||||
|
||||
tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
|
||||
dependencies {
|
||||
testCompile project(':spring-session'),
|
||||
"org.springframework.data:spring-data-redis:$springDataRedisVersion",
|
||||
"org.springframework:spring-websocket:${springVersion}",
|
||||
"org.springframework:spring-messaging:${springVersion}",
|
||||
"org.springframework.security:spring-security-web:${springSecurityVersion}",
|
||||
'junit:junit:4.11',
|
||||
'org.mockito:mockito-core:1.9.5',
|
||||
"org.springframework:spring-test:$springVersion",
|
||||
'org.easytesting:fest-assert:1.4',
|
||||
"com.hazelcast:hazelcast:$hazelcastVersion",
|
||||
"redis.clients:jedis:2.4.1",
|
||||
"javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
}
|
||||
|
||||
asciidoctor {
|
||||
def ghTag = snapshotBuild ? 'master' : project.version
|
||||
def ghUrl = "https://github.com/spring-projects/spring-session/tree/$ghTag/"
|
||||
attributes 'version-snapshot': snapshotBuild,
|
||||
'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' : springVersion,
|
||||
'hazelcast-version' : hazelcastVersion,
|
||||
'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/',
|
||||
|
||||
'source-highlighter' : 'coderay',
|
||||
'imagesdir':'./images',
|
||||
'icons': 'font',
|
||||
'sectanchors':'',
|
||||
'idprefix':'',
|
||||
'idseparator':'-',
|
||||
'docinfo1':'true',
|
||||
'revnumber' : project.version
|
||||
}
|
||||
49
docs/spring-session-docs.gradle
Normal file
@@ -0,0 +1,49 @@
|
||||
apply plugin: 'io.spring.convention.docs'
|
||||
apply plugin: 'io.spring.convention.spring-test'
|
||||
|
||||
dependencies {
|
||||
testCompile project(':spring-session-core')
|
||||
testCompile project(':spring-session-data-redis')
|
||||
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
|
||||
|
||||
asciidoctor {
|
||||
def ghTag = snapshotBuild ? 'master' : project.version
|
||||
def ghUrl = "https://github.com/spring-projects/spring-session/tree/$ghTag"
|
||||
|
||||
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,
|
||||
'version-snapshot': snapshotBuild
|
||||
}
|
||||
@@ -6,8 +6,6 @@ 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: This feature will likely be refactored in the next release to account for https://github.com/spring-projects/spring-session/issues/301[#301]
|
||||
|
||||
|
||||
[[findbyusername-assumptions]]
|
||||
== Assumptions
|
||||
@@ -33,62 +31,28 @@ Consider the following scenario:
|
||||
Wouldn't it be nice if we could allow the user to invalidate the session at the library from any device they authenticate with?
|
||||
This sample demonstrates how this is possible.
|
||||
|
||||
[[findbyusernamesessionrepository]]
|
||||
== FindByUsernameSessionRepository
|
||||
[[findbyindexnamesessionrepository]]
|
||||
== FindByIndexNameSessionRepository
|
||||
|
||||
In order to look up a user by their username, you must first choose a `SessionRepository` that implements <<index.doc#ap-findbyusernamesessionrepository,FindByUsernameSessionRepository>>.
|
||||
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.
|
||||
|
||||
== Mapping the username
|
||||
|
||||
`FindByUsernameSessionRepository` 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 `Session.FindByUsernameSessionRepository` is populated with the username.
|
||||
`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.
|
||||
|
||||
Generally, speaking this can be done with the following code immediately after the user authenticates:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{samples-dir}findbyusername/src/main/java/sample/session/SpringSessionPrincipalNameSuccessHandler.java[tags=set-username]
|
||||
include::{docs-test-dir}docs/FindByIndexNameSessionRepositoryTests.java[tags=set-username]
|
||||
----
|
||||
|
||||
== Mapping the username with Spring Security
|
||||
|
||||
Since we are using Spring Security, it makes perfect sense to provide a custom `AuthenticationSuccessHandler` that populates the username.
|
||||
For example:
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
We plan to provide first class integration with Spring Security to make this process easier in the future.
|
||||
For details track https://github.com/spring-projects/spring-session/issues/266[gh-266].
|
||||
====
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{samples-dir}findbyusername/src/main/java/sample/session/SpringSessionPrincipalNameSuccessHandler.java[tags=class]
|
||||
----
|
||||
|
||||
In order to support multiple handlers, we need to also create a custom `AuthenticationSuccessHandler` that delegates to multiple `AuthenticationSuccessHandler` instances.
|
||||
For example:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{samples-dir}findbyusername/src/main/java/sample/session/CompositeAuthenticationSuccessHandler.java[tags=class]
|
||||
----
|
||||
|
||||
Next we need to provide a custom `AuthenticationSuccessHandler` with Spring Security.
|
||||
In Java configuration, we can do this using the following:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{samples-dir}findbyusername/src/main/java/sample/config/SecurityConfig.java[tags=handler]
|
||||
----
|
||||
|
||||
We can then configure authentication success with the following:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{samples-dir}findbyusername/src/main/java/sample/config/SecurityConfig.java[tags=config]
|
||||
----
|
||||
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.
|
||||
|
||||
== Adding Additional Data to Session
|
||||
|
||||
@@ -101,7 +65,7 @@ For example, our sample application includes the location and access type of the
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{samples-dir}findbyusername/src/main/java/sample/session/SessionDetails.java[tags=class]
|
||||
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`.
|
||||
@@ -109,7 +73,7 @@ For example:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{samples-dir}findbyusername/src/main/java/sample/session/SessionDetailsFilter.java[tags=dofilterinternal]
|
||||
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`.
|
||||
@@ -129,7 +93,7 @@ We can now find all the sessions for a specific user.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{samples-dir}findbyusername/src/main/java/sample/mvc/IndexController.java[tags=findbyusername]
|
||||
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.
|
||||
@@ -144,12 +108,13 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
|
||||
|
||||
[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.
|
||||
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:findbyusername:tomcatRun
|
||||
$ ./gradlew :spring-session-sample-boot-findbyusername:bootRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
127
docs/src/docs/asciidoc/guides/boot-jdbc.adoc
Normal file
@@ -0,0 +1,127 @@
|
||||
= Spring Session - Spring Boot
|
||||
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.
|
||||
|
||||
NOTE: The completed guide can be found 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:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
<dependencies>
|
||||
<!-- ... -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session-jdbc</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
Spring Boot provides dependency management for Spring Session modules, so there's no need to explicitly declare dependency version.
|
||||
|
||||
// tag::config[]
|
||||
|
||||
[[httpsession-jdbc-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 a relational database is as simple as adding a single configuration property to your `application.properties`:
|
||||
|
||||
.src/main/resources/application.properties
|
||||
----
|
||||
spring.session.store-type=jdbc # Session store type.
|
||||
----
|
||||
|
||||
Under the hood, Spring Boot will apply configuration that is equivalent to manually adding `@EnableJdbcHttpSession` annotation.
|
||||
This creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
|
||||
The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
|
||||
|
||||
Further customization is possible using `application.properties`:
|
||||
|
||||
.src/main/resources/application.properties
|
||||
----
|
||||
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds will be used.
|
||||
spring.session.jdbc.initialize-schema=embedded # Database schema initialization mode.
|
||||
spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema.
|
||||
spring.session.jdbc.table-name=SPRING_SESSION # Name of the database table used to store sessions.
|
||||
----
|
||||
|
||||
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-session[Spring Session] portion of the Spring Boot documentation.
|
||||
|
||||
[[httpsession-jdbc-boot-configuration]]
|
||||
== 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*
|
||||
|
||||
.src/main/resources/application.properties
|
||||
----
|
||||
spring.datasource.url= # JDBC URL of the database.
|
||||
spring.datasource.username= # Login username of the database.
|
||||
spring.datasource.password= # Login password of the database.
|
||||
----
|
||||
|
||||
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-configure-datasource[Configure a DataSource] portion of the Spring Boot documentation.
|
||||
|
||||
[[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`.
|
||||
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 Boot takes care of both of these steps for us.
|
||||
|
||||
// end::config[]
|
||||
|
||||
[[httpsession-jdbc-boot-sample]]
|
||||
== 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.
|
||||
|
||||
[[httpsession-jdbc-boot-running]]
|
||||
=== Running the httpsession-jdbc-boot Sample Application
|
||||
|
||||
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
|
||||
|
||||
----
|
||||
$ ./gradlew :spring-session-sample-boot-jdbc:bootRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
|
||||
[[httpsession-jdbc-boot-explore]]
|
||||
=== Exploring the security Sample Application
|
||||
|
||||
Try using the application. Enter the following to log in:
|
||||
|
||||
* **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.
|
||||
|
||||
[[httpsession-jdbc-boot-how]]
|
||||
=== How does it work?
|
||||
|
||||
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in 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 a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
|
||||
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
|
||||
|
||||
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)
|
||||
|
||||
Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated.
|
||||
@@ -1,5 +1,5 @@
|
||||
= Spring Session - Spring Boot
|
||||
Rob Winch
|
||||
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.
|
||||
@@ -20,64 +20,38 @@ If you are using Maven, ensure to add the following dependencies:
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session</artifactId>
|
||||
<version>{spring-session-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-redis</artifactId>
|
||||
<artifactId>spring-session-data-redis</artifactId>
|
||||
</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:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
----
|
||||
<repositories>
|
||||
|
||||
<!-- ... -->
|
||||
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/libs-snapshot</url>
|
||||
</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:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
----
|
||||
<repository>
|
||||
<id>spring-milestone</id>
|
||||
<url>https://repo.spring.io/libs-milestone</url>
|
||||
</repository>
|
||||
----
|
||||
endif::[]
|
||||
Spring Boot provides dependency management for Spring Session modules, so there's no need to explicitly declare dependency version.
|
||||
|
||||
[[boot-spring-configuration]]
|
||||
== Spring Configuration
|
||||
== Spring Boot 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:
|
||||
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`:
|
||||
|
||||
[source,java]
|
||||
.src/main/resources/application.properties
|
||||
----
|
||||
include::{samples-dir}boot/src/main/java/sample/config/HttpSessionConfig.java[tags=class]
|
||||
spring.session.store-type=redis # Session store type.
|
||||
----
|
||||
|
||||
<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
|
||||
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.
|
||||
In this instance Spring Session is backed by Redis.
|
||||
|
||||
Further customization is possible using `application.properties`:
|
||||
|
||||
.src/main/resources/application.properties
|
||||
----
|
||||
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds will be used.
|
||||
spring.session.redis.flush-mode=on-save # Sessions flush mode.
|
||||
spring.session.redis.namespace=spring:session # Namespace for keys used to store sessions.
|
||||
----
|
||||
|
||||
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-session[Spring Session] portion of the Spring Boot documentation.
|
||||
|
||||
[[boot-redis-configuration]]
|
||||
== Configuring the Redis Connection
|
||||
@@ -88,17 +62,17 @@ 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/current/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
|
||||
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
|
||||
|
||||
[[boot-servlet-configuration]]
|
||||
== Servlet Container Initialization
|
||||
|
||||
Our <<boot-spring-configuration,Spring 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.
|
||||
@@ -106,23 +80,24 @@ Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `spring
|
||||
Fortunately, Spring Boot takes care of both of these steps for us.
|
||||
|
||||
[[boot-sample]]
|
||||
== boot Sample Application
|
||||
== 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 using Spring Boot.
|
||||
|
||||
[[boot-running]]
|
||||
=== Running the boot Sample Application
|
||||
=== 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.
|
||||
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:boot:bootRun
|
||||
$ ./gradlew :spring-session-sample-boot-redis:bootRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
@@ -147,13 +122,13 @@ Spring Session replaces the `HttpSession` with an implementation that is backed
|
||||
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]).
|
||||
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
|
||||
|
||||
If you like, you can easily remove the session 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:
|
||||
|
||||
@@ -24,7 +24,7 @@ Please make sure you have already integrated Spring Session with the HttpSession
|
||||
[[websocket-spring-configuration]]
|
||||
== Spring Configuration
|
||||
|
||||
In a typical Spring WebSocket application users would extend `AbstractWebSocketMessageBrokerConfigurer`.
|
||||
In a typical Spring WebSocket application users would implement `WebSocketMessageBrokerConfigurer`.
|
||||
For example, the configuration might look something like the following:
|
||||
|
||||
[source,java]
|
||||
@@ -38,12 +38,12 @@ For example:
|
||||
.src/main/java/samples/config/WebSocketConfig.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}websocket/src/main/java/sample/config/WebSocketConfig.java[tags=class]
|
||||
include::{samples-dir}boot/websocket/src/main/java/sample/config/WebSocketConfig.java[tags=class]
|
||||
----
|
||||
|
||||
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?
|
||||
@@ -73,23 +73,23 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
|
||||
|
||||
[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 removing the comment from the following file before starting the application:
|
||||
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:
|
||||
|
||||
.src/main/java/samples/config/WebSecurityConfig.java
|
||||
[source,java]
|
||||
.src/main/resources/application.properties
|
||||
----
|
||||
include::{samples-dir}websocket/src/main/java/sample/config/WebSecurityConfig.java[tags=enable-redis-httpsession]
|
||||
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 `JedisConnectionFactory` to point to a Redis server.
|
||||
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:websocket:bootRun
|
||||
$ ./gradlew :spring-session-sample-boot-websocket:bootRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
133
docs/src/docs/asciidoc/guides/grails3.adoc
Normal file
@@ -0,0 +1,133 @@
|
||||
= Spring Session - Grails
|
||||
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
|
||||
|
||||
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>>.
|
||||
|
||||
== 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:
|
||||
|
||||
.build.gradle
|
||||
[source,groovy]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
dependencies {
|
||||
compile 'org.springframework.boot:spring-boot-starter-redis'
|
||||
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:
|
||||
|
||||
.build.gradle
|
||||
[source,groovy]
|
||||
----
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://repo.spring.io/libs-snapshot'
|
||||
}
|
||||
}
|
||||
----
|
||||
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:
|
||||
|
||||
.build.gradle
|
||||
[source,groovy]
|
||||
----
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://repo.spring.io/libs-milestone'
|
||||
}
|
||||
}
|
||||
----
|
||||
endif::[]
|
||||
|
||||
[[grails3-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.yml*
|
||||
|
||||
.grails-app/conf/application.yml
|
||||
[source,yml]
|
||||
----
|
||||
spring:
|
||||
redis:
|
||||
host: localhost
|
||||
password: secret
|
||||
port: 6397
|
||||
----
|
||||
|
||||
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
|
||||
|
||||
[[grails3-sample]]
|
||||
== Grails 3 Sample Application
|
||||
|
||||
The Grails 3 Sample Application demonstrates how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using Grails.
|
||||
|
||||
[[grails3-running]]
|
||||
=== Running the Grails 3 Sample Application
|
||||
|
||||
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
|
||||
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
|
||||
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
|
||||
====
|
||||
|
||||
----
|
||||
$ ./gradlew :spring-session-sample-misc-grails3:bootRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/test/index
|
||||
|
||||
[[grails3-explore]]
|
||||
=== Exploring the security Sample Application
|
||||
|
||||
Try using the application. Enter the following to log in:
|
||||
|
||||
* **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 Redis rather than Tomcat's `HttpSession` implementation.
|
||||
|
||||
[[grails3-how]]
|
||||
=== How does it work?
|
||||
|
||||
Instead of using Tomcat's `HttpSession`, we are actually persisting 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 a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
|
||||
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
|
||||
|
||||
If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type:
|
||||
|
||||
$ redis-cli keys '*' | xargs redis-cli del
|
||||
|
||||
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
|
||||
|
||||
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
|
||||
|
||||
$ 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.
|
||||
|
||||
NOTE: Spring Session will not work with grails flash scope without additional work. +
|
||||
See this answer for an explanation: https://stackoverflow.com/a/43311427
|
||||
@@ -17,7 +17,7 @@ You can find an example of customizing Spring Session's cookie below:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}custom-cookie/src/main/java/sample/Config.java[tags=cookie-serializer]
|
||||
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
|
||||
@@ -78,12 +78,13 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
|
||||
|
||||
[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.
|
||||
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:custom-cookie:tomcatRun
|
||||
$ ./gradlew :spring-session-sample-javaconfig-custom-cookie:tomcatRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
@@ -98,4 +99,4 @@ Try using the application. Fill out the form with the following information:
|
||||
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
|
||||
@@ -26,7 +26,7 @@ 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>
|
||||
----
|
||||
@@ -64,6 +64,8 @@ Ensure you have the following in your pom.xml:
|
||||
----
|
||||
endif::[]
|
||||
|
||||
// tag::config[]
|
||||
|
||||
[[security-spring-configuration]]
|
||||
== Spring Configuration
|
||||
|
||||
@@ -79,22 +81,24 @@ 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> We create a `HazelcastInstance` that connects Spring Session to Hazelcast.
|
||||
<2> In order to support retrieval of sessions by principal name index, 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/hazelcast-documentation.html#hazelcast-configuration[reference documentation].
|
||||
For more information on configuring Hazelcast, refer to the http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#hazelcast-configuration[reference documentation].
|
||||
|
||||
== Servlet Container Initialization
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
.src/main/java/sample/SecurityInitializer.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}hazelcast-spring/src/main/java/sample/SecurityInitializer.java[tags=class]
|
||||
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.
|
||||
@@ -106,14 +110,14 @@ You can find an example below:
|
||||
.src/main/java/sample/Initializer.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}hazelcast-spring/src/main/java/sample/Initializer.java[tags=class]
|
||||
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`.
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
// end::config[]
|
||||
|
||||
[[hazelcast-spring-security-sample]]
|
||||
== Hazelcast Spring Security Sample Application
|
||||
@@ -126,11 +130,11 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
|
||||
====
|
||||
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/hazelcast-documentation.html#hazelcast-configuration[reference documentation].
|
||||
http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#hazelcast-configuration[reference documentation].
|
||||
====
|
||||
|
||||
----
|
||||
$ ./gradlew :samples:hazelcast-spring:tomcatRun
|
||||
$ ./gradlew :spring-session-sample-javaconfig-hazelcast:tomcatRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
@@ -153,13 +157,13 @@ Spring Session replaces the `HttpSession` with an implementation that is backed
|
||||
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]).
|
||||
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
|
||||
|
||||
=== Interact with the data store
|
||||
|
||||
If you like, you can remove the session using http://docs.hazelcast.org/docs/latest/manual/html-single/hazelcast-documentation.html#hazelcast-java-client[a Java client],
|
||||
http://docs.hazelcast.org/docs/latest/manual/html-single/hazelcast-documentation.html#other-client-implementations[one of the other clients], or the
|
||||
http://docs.hazelcast.org/docs/latest/manual/html-single/hazelcast-documentation.html#management-center[management center].
|
||||
If you like, you can remove the session using http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#hazelcast-java-client[a Java client],
|
||||
http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#other-client-implementations[one of the other clients], or the
|
||||
http://docs.hazelcast.org/docs/{hazelcast-version}/manual/html-single/index.html#management-center[management center].
|
||||
|
||||
==== Using the console
|
||||
|
||||
@@ -168,7 +172,7 @@ For example, using the management center console after connecting to your Hazelc
|
||||
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/hazelcast-documentation.html#console[the console].
|
||||
TIP: The Hazelcast documentation has instructions for http://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:
|
||||
|
||||
@@ -179,7 +183,7 @@ Now visit the application at http://localhost:8080/ and observe that we are no l
|
||||
==== 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/hazelcast-documentation.html#rest-client[REST API]
|
||||
http://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):
|
||||
@@ -188,4 +192,4 @@ For example, you could delete an individual key as follows (replacing `7e8383a4-
|
||||
|
||||
TIP: The port number of the Hazelcast node will be printed to the console on startup. Replace `xxxxx` above with the port number.
|
||||
|
||||
Now observe that you are no longer authenticated with this session.
|
||||
Now observe that you are no longer authenticated with this session.
|
||||
152
docs/src/docs/asciidoc/guides/java-jdbc.adoc
Normal file
@@ -0,0 +1,152 @@
|
||||
= Spring Session - HttpSession (Quick Start)
|
||||
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` with Java Configuration.
|
||||
|
||||
NOTE: The completed guide can be found 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:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
<dependencies>
|
||||
<!-- ... -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session-jdbc</artifactId>
|
||||
<version>{spring-session-version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<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:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
----
|
||||
<repositories>
|
||||
|
||||
<!-- ... -->
|
||||
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/libs-snapshot</url>
|
||||
</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:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
----
|
||||
<repository>
|
||||
<id>spring-milestone</id>
|
||||
<url>https://repo.spring.io/libs-milestone</url>
|
||||
</repository>
|
||||
----
|
||||
endif::[]
|
||||
|
||||
// tag::config[]
|
||||
|
||||
[[httpsession-jdbc-spring-configuration]]
|
||||
== 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:
|
||||
|
||||
[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.
|
||||
<3> We create a `transactionManager` that manages transactions for previously configured `dataSource`.
|
||||
|
||||
For additional information on how to configure data access related concerns, please refer to the https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/data-access.html[Spring Framework Reference Documentation].
|
||||
|
||||
== Java Servlet Container Initialization
|
||||
|
||||
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:
|
||||
|
||||
.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`.
|
||||
|
||||
<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`.
|
||||
|
||||
// end::config[]
|
||||
|
||||
[[httpsession-jdbc-sample]]
|
||||
== httpsession-jdbc Sample Application
|
||||
|
||||
=== Running the httpsession-jdbc Sample Application
|
||||
|
||||
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
|
||||
|
||||
----
|
||||
$ ./gradlew :spring-session-sample-javaconfig-jdbc:tomcatRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
|
||||
=== Exploring the httpsession-jdbc Sample Application
|
||||
|
||||
Try using the application. Fill out the form with the following information:
|
||||
|
||||
* **Attribute Name:** _username_
|
||||
* **Attribute Value:** _rob_
|
||||
|
||||
Now click the **Set Attribute** button. You should now see the values displayed in the table.
|
||||
|
||||
=== How does it work?
|
||||
|
||||
We interact with the standard `HttpSession` in the `SessionServlet` shown below:
|
||||
|
||||
.src/main/java/sample/SessionServlet.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}javaconfig/jdbc/src/main/java/sample/SessionServlet.java[tags=class]
|
||||
----
|
||||
|
||||
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database.
|
||||
Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
|
||||
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
|
||||
|
||||
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)
|
||||
|
||||
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
|
||||
@@ -23,10 +23,15 @@ If you are using Maven, ensure to add the following dependencies:
|
||||
<version>{spring-session-version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
<version>{lettuce-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>{spring-version}</version>
|
||||
<version>{spring-framework-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
@@ -75,7 +80,7 @@ Add the following Spring Configuration:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}httpsession/src/main/java/sample/Config.java[tags=class]
|
||||
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.
|
||||
@@ -83,7 +88,7 @@ The filter is what is in charge of replacing the `HttpSession` implementation to
|
||||
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, refer to the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
|
||||
|
||||
== Java Servlet Container Initialization
|
||||
|
||||
@@ -98,7 +103,7 @@ You can find an example below:
|
||||
.src/main/java/sample/Initializer.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}httpsession/src/main/java/sample/Initializer.java[tags=class]
|
||||
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`.
|
||||
@@ -120,12 +125,13 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
|
||||
|
||||
[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.
|
||||
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:tomcatRun
|
||||
$ ./gradlew :spring-session-sample-javaconfig-redis:tomcatRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
@@ -146,21 +152,21 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
|
||||
.src/main/java/sample/SessionServlet.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}httpsession/src/main/java/sample/SessionServlet.java[tags=class]
|
||||
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]).
|
||||
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
|
||||
|
||||
If you like, you can easily remove the session 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:
|
||||
|
||||
$ 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 visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
|
||||
@@ -23,10 +23,15 @@ If you are using Maven, ensure to add the following dependencies:
|
||||
<version>{spring-session-version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
<version>{lettuce-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>{spring-version}</version>
|
||||
<version>{spring-framework-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
@@ -75,7 +80,7 @@ Add the following Spring Configuration:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}rest/src/main/java/sample/HttpSessionConfig.java[tags=class]
|
||||
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`.
|
||||
@@ -83,7 +88,7 @@ The filter is what is in charge of replacing the `HttpSession` implementation to
|
||||
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, refer to 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
|
||||
@@ -96,7 +101,7 @@ In order for our `Filter` to do its magic, Spring needs to load our `Config` cla
|
||||
.src/main/java/sample/mvc/MvcInitializer.java
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{samples-dir}rest/src/main/java/sample/mvc/MvcInitializer.java[tags=config]
|
||||
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.
|
||||
@@ -105,7 +110,7 @@ Fortunately, Spring Session provides a utility class named `AbstractHttpSessionA
|
||||
.src/main/java/sample/Initializer.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}rest/src/main/java/sample/Initializer.java[tags=class]
|
||||
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`.
|
||||
@@ -121,12 +126,13 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
|
||||
|
||||
[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.
|
||||
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/
|
||||
@@ -149,7 +155,7 @@ In the output you will notice the following:
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
...
|
||||
x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3
|
||||
X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3
|
||||
|
||||
{"username":"user"}
|
||||
----
|
||||
@@ -157,25 +163,25 @@ x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3
|
||||
Specifically, we 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
|
||||
* We have a header with the name of *X-Auth-Token* which 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 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 outputs the username just as before:
|
||||
|
||||
$ curl -v http://localhost:8080/ -H "x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
|
||||
$ 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.
|
||||
|
||||
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, then the X-Auth-Token is displayed in the response with an empty value. For example, the following will invalidate our session:
|
||||
|
||||
$ curl -v http://localhost:8080/logout -H "x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
|
||||
$ 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 will 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:
|
||||
X-Auth-Token:
|
||||
----
|
||||
|
||||
=== How does it work?
|
||||
@@ -183,7 +189,7 @@ x-auth-token:
|
||||
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 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:
|
||||
|
||||
@@ -194,7 +200,7 @@ In the output you will notice the following:
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
...
|
||||
x-auth-token: 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
|
||||
X-Auth-Token: 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
|
||||
|
||||
{"username":"user"}
|
||||
----
|
||||
@@ -203,12 +209,12 @@ Now remove the session using redis-cli. For example, on a Linux based system you
|
||||
|
||||
$ 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:
|
||||
|
||||
$ 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 are prompted for a authentication. For example, the following returns an HTTP 401:
|
||||
|
||||
$ curl -v http://localhost:8080/ -H "x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
|
||||
$ curl -v http://localhost:8080/ -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
|
||||
@@ -19,15 +19,20 @@ If you are using Maven, ensure to add the following dependencies:
|
||||
<!-- ... -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session-data-redis</artifactId>
|
||||
<version>{spring-session-version}</version>
|
||||
<type>pom</type>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session-data-redis</artifactId>
|
||||
<version>{spring-session-version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>{spring-version}</version>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
<version>{lettuce-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>{spring-framework-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
@@ -74,7 +79,7 @@ Add the following Spring Configuration:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}security/src/main/java/sample/Config.java[tags=class]
|
||||
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.
|
||||
@@ -82,7 +87,7 @@ The filter is what is in charge of replacing the `HttpSession` implementation to
|
||||
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, refer to the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
|
||||
|
||||
== Servlet Container Initialization
|
||||
|
||||
@@ -95,7 +100,7 @@ Since our application is already loading Spring configuration using our `Securit
|
||||
.src/main/java/sample/SecurityInitializer.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}security/src/main/java/sample/SecurityInitializer.java[tags=class]
|
||||
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.
|
||||
@@ -107,7 +112,7 @@ You can find an example below:
|
||||
.src/main/java/sample/Initializer.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}security/src/main/java/sample/Initializer.java[tags=class]
|
||||
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`.
|
||||
@@ -125,12 +130,13 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
|
||||
|
||||
[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.
|
||||
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:security:tomcatRun
|
||||
$ ./gradlew :spring-session-sample-javaconfig-security:tomcatRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
@@ -153,16 +159,16 @@ Spring Session replaces the `HttpSession` with an implementation that is backed
|
||||
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]).
|
||||
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
|
||||
|
||||
If you like, you can easily remove the session 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:
|
||||
|
||||
$ 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 visit the application at http://localhost:8080/ and observe that we are no longer authenticated.
|
||||
@@ -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 `JedisConnectionFactory` 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}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}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}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[]
|
||||
162
docs/src/docs/asciidoc/guides/xml-jdbc.adoc
Normal file
@@ -0,0 +1,162 @@
|
||||
= Spring Session - HttpSession (Quick Start)
|
||||
Rob Winch, Vedran Pavić
|
||||
:toc:
|
||||
|
||||
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>>.
|
||||
|
||||
== 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:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
<dependencies>
|
||||
<!-- ... -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session-jdbc</artifactId>
|
||||
<version>{spring-session-version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<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:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
----
|
||||
<repositories>
|
||||
|
||||
<!-- ... -->
|
||||
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/libs-snapshot</url>
|
||||
</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:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
----
|
||||
<repository>
|
||||
<id>spring-milestone</id>
|
||||
<url>https://repo.spring.io/libs-milestone</url>
|
||||
</repository>
|
||||
----
|
||||
endif::[]
|
||||
|
||||
// tag::config[]
|
||||
|
||||
[[httpsession-jdbc-xml-spring-configuration]]
|
||||
== 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:
|
||||
|
||||
.src/main/webapp/WEB-INF/spring/session.xml
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/spring/session.xml[tags=beans]
|
||||
----
|
||||
|
||||
<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.
|
||||
<3> We create a `transactionManager` that manages transactions for previously configured `dataSource`.
|
||||
|
||||
For additional information on how to configure data access related concerns, please refer to the https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/data-access.html[Spring Framework Reference Documentation].
|
||||
|
||||
== XML Servlet Container Initialization
|
||||
|
||||
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:
|
||||
|
||||
|
||||
.src/main/webapp/WEB-INF/web.xml
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=context-param]
|
||||
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=listeners]
|
||||
----
|
||||
|
||||
The https://docs.spring.io/spring/docs/{spring-framework-version}/spring-framework-reference/core.html#context-create[ContextLoaderListener] reads the contextConfigLocation and picks up our session.xml configuration.
|
||||
|
||||
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
|
||||
The following snippet performs this last step for us:
|
||||
|
||||
.src/main/webapp/WEB-INF/web.xml
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
|
||||
----
|
||||
|
||||
The https://docs.spring.io/spring-framework/docs/{spring-framework-version}/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`.
|
||||
For every request that `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` will be invoked.
|
||||
|
||||
// end::config[]
|
||||
|
||||
[[httpsession-jdbc-xml-sample]]
|
||||
== httpsession-jdbc-xml Sample Application
|
||||
|
||||
=== Running the httpsession-jdbc-xml Sample Application
|
||||
|
||||
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
|
||||
|
||||
----
|
||||
$ ./gradlew :spring-session-sample-xml-jdbc:tomcatRun
|
||||
----
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
|
||||
=== Exploring the httpsession-jdbc-xml Sample Application
|
||||
|
||||
Try using the application. Fill out the form with the following information:
|
||||
|
||||
* **Attribute Name:** _username_
|
||||
* **Attribute Value:** _rob_
|
||||
|
||||
Now click the **Set Attribute** button. You should now see the values displayed in the table.
|
||||
|
||||
=== How does it work?
|
||||
|
||||
We interact with the standard `HttpSession` in the `SessionServlet` shown below:
|
||||
|
||||
.src/main/java/sample/SessionServlet.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}xml/jdbc/src/main/java/sample/SessionServlet.java[tags=class]
|
||||
----
|
||||
|
||||
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database.
|
||||
Spring Session creates a cookie named SESSION in your browser that contains the id of your session.
|
||||
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
|
||||
|
||||
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)
|
||||
|
||||
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
|
||||
@@ -23,10 +23,15 @@ If you are using Maven, ensure to add the following dependencies:
|
||||
<version>{spring-session-version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
<version>{lettuce-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>{spring-version}</version>
|
||||
<version>{spring-framework-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
@@ -76,7 +81,7 @@ Add the following Spring Configuration:
|
||||
.src/main/webapp/WEB-INF/spring/session.xml
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/spring/session.xml[tags=beans]
|
||||
include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/spring/session.xml[tags=beans]
|
||||
----
|
||||
|
||||
<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]).
|
||||
@@ -85,7 +90,7 @@ The filter is what is in charge of replacing the `HttpSession` implementation to
|
||||
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, refer to the https://docs.spring.io/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].
|
||||
|
||||
== XML Servlet Container Initialization
|
||||
|
||||
@@ -99,11 +104,11 @@ We do this with the following configuration:
|
||||
.src/main/webapp/WEB-INF/web.xml
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/web.xml[tags=context-param]
|
||||
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/web.xml[tags=listeners]
|
||||
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.
|
||||
The following snippet performs this last step for us:
|
||||
@@ -111,10 +116,10 @@ The following snippet performs this last step for us:
|
||||
.src/main/webapp/WEB-INF/web.xml
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
|
||||
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`.
|
||||
The https://docs.spring.io/spring-framework/docs/{spring-framework-version}/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`.
|
||||
For every request that `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` will be invoked.
|
||||
|
||||
// end::config[]
|
||||
@@ -128,12 +133,13 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
|
||||
|
||||
[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.
|
||||
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/
|
||||
@@ -154,21 +160,21 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
|
||||
.src/main/java/sample/SessionServlet.java
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}httpsession-xml/src/main/java/sample/SessionServlet.java[tags=class]
|
||||
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]).
|
||||
Go ahead and view the cookies (click for help with https://developers.google.com/web/tools/chrome-devtools/manage-data/cookies[Chrome] or https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector[Firefox]).
|
||||
|
||||
If you like, you can easily remove the session 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:
|
||||
|
||||
$ 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 visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
|
||||
20
docs/src/main/java/docs/Docs.java
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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.
|
||||
*/
|
||||
|
||||
package docs;
|
||||
|
||||
public class Docs {
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package docs;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class FindByIndexNameSessionRepositoryTests {
|
||||
@Mock
|
||||
FindByIndexNameSessionRepository<Session> sessionRepository;
|
||||
@Mock
|
||||
Session session;
|
||||
|
||||
@Test
|
||||
public void setUsername() {
|
||||
// tag::set-username[]
|
||||
String username = "username";
|
||||
this.session.setAttribute(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);
|
||||
// end::set-username[]
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unused")
|
||||
public void findByUsername() {
|
||||
// tag::findby-username[]
|
||||
String username = "username";
|
||||
Map<String, Session> sessionIdToSession = this.sessionRepository
|
||||
.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
|
||||
username);
|
||||
// end::findby-username[]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -13,37 +13,38 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docs;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
package docs;
|
||||
|
||||
import org.junit.Test;
|
||||
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;
|
||||
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() {
|
||||
assertThat(filter).isNotNull();
|
||||
assertThat(this.filter).isNotNull();
|
||||
}
|
||||
|
||||
|
||||
static RedisConnectionFactory connectionFactory() {
|
||||
return mock(RedisConnectionFactory.class);
|
||||
}
|
||||
|
||||
@@ -1,44 +1,63 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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
|
||||
* 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
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package docs;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
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 org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
|
||||
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;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
public class IndexDocTests {
|
||||
static final String ATTR_USER = "user";
|
||||
|
||||
@Test
|
||||
public void repositoryDemo() {
|
||||
ExpiringRepositoryDemo<ExpiringSession> demo = new ExpiringRepositoryDemo<ExpiringSession>();
|
||||
demo.repository = new MapSessionRepository();
|
||||
RepositoryDemo<MapSession> demo = new RepositoryDemo<>();
|
||||
demo.repository = new MapSessionRepository(new ConcurrentHashMap<>());
|
||||
|
||||
demo.demo();
|
||||
}
|
||||
@@ -48,15 +67,15 @@ public class IndexDocTests {
|
||||
private SessionRepository<S> repository; // <1>
|
||||
|
||||
public void demo() {
|
||||
S toSave = repository.createSession(); // <2>
|
||||
S toSave = this.repository.createSession(); // <2>
|
||||
|
||||
// <3>
|
||||
User rwinch = new User("rwinch");
|
||||
toSave.setAttribute(ATTR_USER, rwinch);
|
||||
|
||||
repository.save(toSave); // <4>
|
||||
this.repository.save(toSave); // <4>
|
||||
|
||||
S session = repository.getSession(toSave.getId()); // <5>
|
||||
S session = this.repository.findById(toSave.getId()); // <5>
|
||||
|
||||
// <6>
|
||||
User user = session.getAttribute(ATTR_USER);
|
||||
@@ -67,27 +86,26 @@ public class IndexDocTests {
|
||||
}
|
||||
// end::repository-demo[]
|
||||
|
||||
|
||||
@Test
|
||||
public void expireRepositoryDemo() {
|
||||
ExpiringRepositoryDemo<ExpiringSession> demo = new ExpiringRepositoryDemo<ExpiringSession>();
|
||||
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 = repository.createSession(); // <2>
|
||||
S toSave = this.repository.createSession(); // <2>
|
||||
// ...
|
||||
toSave.setMaxInactiveIntervalInSeconds(30); // <3>
|
||||
toSave.setMaxInactiveInterval(Duration.ofSeconds(30)); // <3>
|
||||
|
||||
repository.save(toSave); // <4>
|
||||
this.repository.save(toSave); // <4>
|
||||
|
||||
S session = repository.getSession(toSave.getId()); // <5>
|
||||
S session = this.repository.findById(toSave.getId()); // <5>
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -96,21 +114,80 @@ public class IndexDocTests {
|
||||
// end::expire-repository-demo[]
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unused")
|
||||
public void newRedisOperationsSessionRepository() {
|
||||
// tag::new-redisoperationssessionrepository[]
|
||||
JedisConnectionFactory factory = new JedisConnectionFactory();
|
||||
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[]
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unused")
|
||||
public void newJdbcOperationsSessionRepository() {
|
||||
// tag::new-jdbcoperationssessionrepository[]
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate();
|
||||
|
||||
// ... configure JdbcTemplate ...
|
||||
|
||||
PlatformTransactionManager transactionManager = new DataSourceTransactionManager();
|
||||
|
||||
// ... configure transactionManager ...
|
||||
|
||||
SessionRepository<? extends Session> repository =
|
||||
new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
|
||||
// end::new-jdbcoperationssessionrepository[]
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unused")
|
||||
public void newHazelcastSessionRepository() {
|
||||
// tag::new-hazelcastsessionrepository[]
|
||||
|
||||
Config config = new Config();
|
||||
|
||||
// ... configure Hazelcast ...
|
||||
|
||||
HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(config);
|
||||
|
||||
HazelcastSessionRepository repository =
|
||||
new HazelcastSessionRepository(hazelcastInstance);
|
||||
// end::new-hazelcastsessionrepository[]
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runSpringHttpSessionConfig() {
|
||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
@@ -120,12 +197,14 @@ public class IndexDocTests {
|
||||
|
||||
try {
|
||||
context.getBean(SessionRepositoryFilter.class);
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static class User {
|
||||
private User(String username) {}
|
||||
private static final class User {
|
||||
private User(String username) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -13,31 +13,34 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docs;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
package docs;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@WebAppConfiguration
|
||||
public class RedisHttpSessionConfigurationNoOpConfigureRedisActionTests {
|
||||
|
||||
@Test
|
||||
public void redisConnectionFactoryNotUsedSinceNoValidation() {}
|
||||
public void redisConnectionFactoryNotUsedSinceNoValidation() {
|
||||
}
|
||||
|
||||
@EnableRedisHttpSession
|
||||
@Configuration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -13,8 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package docs;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.MapSessionRepository;
|
||||
@@ -26,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[]
|
||||
// end::class[]
|
||||
|
||||
34
docs/src/test/java/docs/SpringWebSessionConfig.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package docs;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.session.ReactiveMapSessionRepository;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
import org.springframework.session.config.annotation.web.server.EnableSpringWebSession;
|
||||
|
||||
// tag::class[]
|
||||
@EnableSpringWebSession
|
||||
public class SpringWebSessionConfig {
|
||||
@Bean
|
||||
public ReactiveSessionRepository reactiveSessionRepository() {
|
||||
return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -13,14 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package docs.http;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
@@ -29,14 +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
|
||||
@@ -49,25 +55,32 @@ public abstract class AbstractHttpSessionListenerTests {
|
||||
public void springSessionDestroyedTranslatedToSpringSecurityDestroyed() {
|
||||
Session session = new MapSession();
|
||||
|
||||
publisher.publishEvent(new org.springframework.session.events.SessionDestroyedEvent(this, session));
|
||||
this.publisher.publishEvent(
|
||||
new org.springframework.session.events.SessionDestroyedEvent(this,
|
||||
session));
|
||||
|
||||
assertThat(listener.getEvent().getId()).isEqualTo(session.getId());
|
||||
assertThat(this.listener.getEvent().getId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
static RedisConnectionFactory createMockRedisConnection() {
|
||||
RedisConnectionFactory factory = mock(RedisConnectionFactory.class);
|
||||
RedisConnection connection = mock(RedisConnection.class);
|
||||
|
||||
when(factory.getConnection()).thenReturn(connection);
|
||||
given(factory.getConnection()).willReturn(connection);
|
||||
given(connection.getConfig(anyString())).willReturn(new Properties());
|
||||
return factory;
|
||||
}
|
||||
|
||||
static class SecuritySessionDestroyedListener implements ApplicationListener<SessionDestroyedEvent> {
|
||||
static class SecuritySessionDestroyedListener
|
||||
implements ApplicationListener<SessionDestroyedEvent> {
|
||||
|
||||
private SessionDestroyedEvent event;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.
|
||||
* springframework.context.ApplicationEvent)
|
||||
*/
|
||||
@Override
|
||||
public void onApplicationEvent(SessionDestroyedEvent event) {
|
||||
@@ -75,7 +88,7 @@ public abstract class AbstractHttpSessionListenerTests {
|
||||
}
|
||||
|
||||
public SessionDestroyedEvent getEvent() {
|
||||
return event;
|
||||
return this.event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -13,24 +13,41 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package docs.http;
|
||||
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.config.MapAttributeConfig;
|
||||
import com.hazelcast.config.MapIndexConfig;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.hazelcast.HazelcastSessionRepository;
|
||||
import org.springframework.session.hazelcast.PrincipalNameExtractor;
|
||||
import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession;
|
||||
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
//tag::config[]
|
||||
@EnableHazelcastHttpSession // <1>
|
||||
@Configuration
|
||||
public class HazelcastHttpSessionConfig {
|
||||
|
||||
@Bean
|
||||
public HazelcastInstance embeddedHazelcast() {
|
||||
Config hazelcastConfig = new Config();
|
||||
return Hazelcast.newHazelcastInstance(hazelcastConfig); // <2>
|
||||
public HazelcastInstance hazelcastInstance() {
|
||||
MapAttributeConfig attributeConfig = new MapAttributeConfig()
|
||||
.setName(HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
|
||||
.setExtractor(PrincipalNameExtractor.class.getName());
|
||||
|
||||
Config config = new Config();
|
||||
|
||||
config.getMapConfig(HazelcastSessionRepository.DEFAULT_SESSION_MAP_NAME) // <2>
|
||||
.addMapAttributeConfig(attributeConfig)
|
||||
.addMapIndexConfig(new MapIndexConfig(
|
||||
HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false));
|
||||
|
||||
return Hazelcast.newHazelcastInstance(config); // <3>
|
||||
}
|
||||
|
||||
}
|
||||
// end::config[]
|
||||
// end::config[]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package docs.http;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package docs.http;
|
||||
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package docs.http;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -32,4 +33,4 @@ public class RedisHttpSessionConfig {
|
||||
|
||||
// ...
|
||||
}
|
||||
// end::config[]
|
||||
// end::config[]
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
@EnableSpringHttpSession
|
||||
public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
// @formatter:off
|
||||
// tag::http-rememberme[]
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// ... additional configuration ...
|
||||
.rememberMe()
|
||||
.rememberMeServices(rememberMeServices());
|
||||
// end::http-rememberme[]
|
||||
|
||||
http
|
||||
.formLogin().and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated();
|
||||
}
|
||||
|
||||
// tag::rememberme-bean[]
|
||||
@Bean
|
||||
RememberMeServices rememberMeServices() {
|
||||
SpringSessionRememberMeServices rememberMeServices =
|
||||
new SpringSessionRememberMeServices();
|
||||
// optionally customize
|
||||
rememberMeServices.setAlwaysRemember(true);
|
||||
return rememberMeServices;
|
||||
}
|
||||
// end::rememberme-bean[]
|
||||
// @formatter:on
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public InMemoryUserDetailsManager userDetailsService() {
|
||||
return new InMemoryUserDetailsManager(User.withUsername("user")
|
||||
.password("{noop}password").roles("USER").build());
|
||||
}
|
||||
|
||||
@Bean
|
||||
MapSessionRepository sessionRepository() {
|
||||
return new MapSessionRepository(new ConcurrentHashMap<>());
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package docs.security;
|
||||
|
||||
import java.net.HttpCookie;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
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.SpringRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = RememberMeSecurityConfiguration.class)
|
||||
@WebAppConfiguration
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class RememberMeSecurityConfigurationTests<T extends Session> {
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
@Autowired
|
||||
SessionRepositoryFilter springSessionRepositoryFilter;
|
||||
@Autowired
|
||||
SessionRepository<T> sessions;
|
||||
|
||||
MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
// @formatter:off
|
||||
this.mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup(this.context)
|
||||
.addFilters(this.springSessionRepositoryFilter)
|
||||
.apply(springSecurity())
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenSpringSessionRememberMeEnabledThenCookieMaxAgeAndSessionExpirationSet()
|
||||
throws Exception {
|
||||
// @formatter:off
|
||||
MvcResult result = this.mockMvc
|
||||
.perform(formLogin())
|
||||
.andReturn();
|
||||
// @formatter:on
|
||||
|
||||
HttpCookie cookie = getSessionCookie(result.getResponse());
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
T session = this.sessions
|
||||
.findById(new String(Base64.getDecoder().decode(cookie.getValue())));
|
||||
assertThat(session.getMaxInactiveInterval())
|
||||
.isEqualTo(Duration.ofDays(30));
|
||||
|
||||
}
|
||||
|
||||
private HttpCookie getSessionCookie(HttpServletResponse response) {
|
||||
for (HttpCookie cookie : HttpCookie.parse(response.getHeader(HttpHeaders.SET_COOKIE))) {
|
||||
if ("SESSION".equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package docs.security;
|
||||
|
||||
import java.net.HttpCookie;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
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.SpringRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@WebAppConfiguration
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class RememberMeSecurityConfigurationXmlTests<T extends Session> {
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
@Autowired
|
||||
SessionRepositoryFilter springSessionRepositoryFilter;
|
||||
@Autowired
|
||||
SessionRepository<T> sessions;
|
||||
|
||||
MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
// @formatter:off
|
||||
this.mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup(this.context)
|
||||
.addFilters(this.springSessionRepositoryFilter)
|
||||
.apply(springSecurity())
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenSpringSessionRememberMeEnabledThenCookieMaxAgeAndSessionExpirationSet()
|
||||
throws Exception {
|
||||
// @formatter:off
|
||||
MvcResult result = this.mockMvc
|
||||
.perform(formLogin())
|
||||
.andReturn();
|
||||
// @formatter:on
|
||||
|
||||
HttpCookie cookie = getSessionCookie(result.getResponse());
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
T session = this.sessions
|
||||
.findById(new String(Base64.getDecoder().decode(cookie.getValue())));
|
||||
assertThat(session.getMaxInactiveInterval())
|
||||
.isEqualTo(Duration.ofDays(30));
|
||||
|
||||
}
|
||||
|
||||
private HttpCookie getSessionCookie(HttpServletResponse response) {
|
||||
for (HttpCookie cookie : HttpCookie.parse(response.getHeader(HttpHeaders.SET_COOKIE))) {
|
||||
if ("SESSION".equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
||||
54
docs/src/test/java/docs/security/SecurityConfiguration.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package docs.security;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
|
||||
|
||||
/**
|
||||
* @author Joris Kuipers
|
||||
*/
|
||||
// tag::class[]
|
||||
@Configuration
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private FindByIndexNameSessionRepository<Session> sessionRepository;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
// other config goes here...
|
||||
.sessionManagement()
|
||||
.maximumSessions(2)
|
||||
.sessionRegistry(sessionRegistry());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpringSessionBackedSessionRegistry sessionRegistry() {
|
||||
return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -1,40 +1,40 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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
|
||||
* 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
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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
|
||||
*/
|
||||
* @author Rob Winch
|
||||
*/
|
||||
// tag::class[]
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
@EnableWebSocketMessageBroker
|
||||
public class WebSocketConfig
|
||||
extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/messages")
|
||||
.withSockJS();
|
||||
registry.addEndpoint("/messages").withSockJS();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,4 +43,4 @@ public class WebSocketConfig
|
||||
registry.setApplicationDestinationPrefixes("/app");
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
// end::class[]
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
|
||||
<bean class="docs.HttpSessionConfigurationNoOpConfigureRedisActionXmlTests"
|
||||
factory-method="connectionFactory"/>
|
||||
</beans>
|
||||
</beans>
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
<bean class="docs.http.AbstractHttpSessionListenerTests"
|
||||
factory-method="createMockRedisConnection"/>
|
||||
<bean class="docs.http.AbstractHttpSessionListenerTests$SecuritySessionDestroyedListener"/>
|
||||
</beans>
|
||||
</beans>
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-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"
|
||||
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">
|
||||
|
||||
<!-- tag::config[] -->
|
||||
<security:http>
|
||||
<!-- ... -->
|
||||
<security:form-login />
|
||||
<security:remember-me services-ref="rememberMeServices"/>
|
||||
</security:http>
|
||||
|
||||
<bean id="rememberMeServices"
|
||||
class="org.springframework.session.security.web.authentication.SpringSessionRememberMeServices"
|
||||
p:alwaysRemember="true"/>
|
||||
<!-- end::config[] -->
|
||||
|
||||
|
||||
<security:user-service>
|
||||
<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">
|
||||
<constructor-arg>
|
||||
<bean class="java.util.concurrent.ConcurrentHashMap"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</beans>
|
||||
22
docs/src/test/resources/docs/security/security-config.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-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">
|
||||
|
||||
<!-- tag::config[] -->
|
||||
<security:http>
|
||||
<!-- other config goes here... -->
|
||||
<security:session-management>
|
||||
<security:concurrency-control max-sessions="2" session-registry-ref="sessionRegistry"/>
|
||||
</security:session-management>
|
||||
</security:http>
|
||||
|
||||
<bean id="sessionRegistry"
|
||||
class="org.springframework.session.security.SpringSessionBackedSessionRegistry">
|
||||
<constructor-arg ref="sessionRepository"/>
|
||||
</bean>
|
||||
<!-- end::config[] -->
|
||||
|
||||
</beans>
|
||||
12
etc/checkstyle/checkstyle.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?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">
|
||||
<!-- Supressions -->
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${configDir}/suppressions.xml"/>
|
||||
</module>
|
||||
|
||||
<!-- Root Checks -->
|
||||
<module name="io.spring.javaformat.checkstyle.SpringChecks"/>
|
||||
</module>
|
||||
16
etc/checkstyle/header.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
^\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$
|
||||
^.*$
|
||||
16
etc/checkstyle/suppressions.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN"
|
||||
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
|
||||
<suppressions>
|
||||
<!-- global -->
|
||||
<suppress files="[\\/]src[\\/]integration-test[\\/]java[\\/]" checks="Javadoc*"/>
|
||||
|
||||
<!-- docs -->
|
||||
<suppress files="[\\/]docs[\\/]" checks="Javadoc*"/>
|
||||
<suppress files="[\\/]docs[\\/]" checks="AvoidStaticImport"/>
|
||||
<suppress files="[\\/]docs[\\/]" checks="InnerTypeLast"/>
|
||||
|
||||
<!-- samples -->
|
||||
<suppress files="[\\/]samples[\\/]" checks="Javadoc*"/>
|
||||
<suppress files="[\\/]samples[\\/].+Application\.java" checks="HideUtilityClassConstructor"/>
|
||||
</suppressions>
|
||||
11
etc/eclipse/.checkstyle
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
|
||||
<local-check-config name="Spring Session Checkstyle" location="${configDir}/checkstyle.xml" type="external" description="">
|
||||
<property name="configDir" value="${configDir}"/>
|
||||
<additional-data name="protect-config-file" value="false"/>
|
||||
</local-check-config>
|
||||
<fileset name="all" enabled="true" check-config-name="Spring Session Checkstyle" local="true">
|
||||
<file-match-pattern match-pattern="." include-pattern="true"/>
|
||||
</fileset>
|
||||
</fileset-config>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="12">
|
||||
<profile kind="CodeFormatterProfile" name="Spring" version="12">
|
||||
<profile kind="CodeFormatterProfile" name="Spring Session Java Conventions" version="12">
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
||||
@@ -13,7 +13,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
@@ -31,9 +31,9 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
@@ -65,7 +65,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="90"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
@@ -79,7 +79,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
@@ -133,7 +133,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
@@ -161,7 +161,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
@@ -175,9 +175,9 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
@@ -202,7 +202,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
@@ -266,7 +266,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
@@ -283,7 +283,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
391
etc/eclipse/org.eclipse.jdt.core.prefs
Normal file
@@ -0,0 +1,391 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.codeComplete.argumentPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.argumentSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.fieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.fieldSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.localPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.localSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.doc.comment.support=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deadCode=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=default
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=default
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.processAnnotations=disabled
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=false
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=90
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=2
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.lineSplit=90
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=tab
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=true
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
org.eclipse.jdt.core.javaFormatter=org.springframework.ide.eclipse.jdt.formatter.javaformatter
|
||||
125
etc/eclipse/org.eclipse.jdt.ui.prefs
Normal file
@@ -1,16 +1,2 @@
|
||||
springSecurityVersion=4.0.0.RELEASE
|
||||
junitVersion=4.11
|
||||
jstlVersion=1.2.1
|
||||
jedisVersion=2.5.2
|
||||
springVersion=4.1.6.RELEASE
|
||||
groovyVersion=2.3.11
|
||||
version=1.1.0.M1
|
||||
seleniumVersion=2.44.0
|
||||
jacksonVersion=2.4.5
|
||||
gebVersion=0.10.0
|
||||
jspApiVersion=2.0
|
||||
servletApiVersion=3.0.1
|
||||
spockVersion=0.7-groovy-2.0
|
||||
commonsPoolVersion=2.2
|
||||
springDataRedisVersion=1.4.2.RELEASE
|
||||
hazelcastVersion=3.5.1
|
||||
springBootVersion=2.0.3.RELEASE
|
||||
version=2.1.0.M1
|
||||
|
||||
31
gradle/dependency-management.gradle
Normal file
@@ -0,0 +1,31 @@
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.6'
|
||||
mavenBom 'io.projectreactor:reactor-bom:Californium-M1'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.1.0.RC1'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Lovelace-RC1'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.1.0.M2'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.8.1'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dependencySet(group: 'com.hazelcast', version: '3.10.3') {
|
||||
entry 'hazelcast'
|
||||
entry 'hazelcast-client'
|
||||
}
|
||||
|
||||
dependency 'com.h2database:h2:1.4.197'
|
||||
dependency 'com.microsoft.sqlserver:mssql-jdbc:6.4.0.jre8'
|
||||
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
|
||||
dependency 'io.lettuce:lettuce-core:5.1.0.M1'
|
||||
dependency 'javax.servlet:javax.servlet-api:3.1.0'
|
||||
dependency 'junit:junit:4.12'
|
||||
dependency 'mysql:mysql-connector-java:8.0.11'
|
||||
dependency 'org.apache.derby:derby:10.14.2.0'
|
||||
dependency 'org.assertj:assertj-core:3.10.0'
|
||||
dependency 'org.hsqldb:hsqldb:2.4.1'
|
||||
dependency 'org.mariadb.jdbc:mariadb-java-client:2.2.6'
|
||||
dependency 'org.mockito:mockito-core:2.20.1'
|
||||
dependency 'org.postgresql:postgresql:42.2.4'
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'javadocHotfix'
|
||||
apply plugin: 'eclipse-wtp'
|
||||
apply plugin: 'propdeps'
|
||||
apply plugin: 'propdeps-idea'
|
||||
apply plugin: 'propdeps-eclipse'
|
||||
|
||||
group = 'org.springframework.session'
|
||||
|
||||
sourceCompatibility = 1.5
|
||||
targetCompatibility = 1.5
|
||||
|
||||
ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : 'latest.integration'
|
||||
|
||||
ext.spockDependencies = [
|
||||
dependencies.create("org.spockframework:spock-core:$spockVersion") {
|
||||
exclude group: 'junit', module: 'junit-dep'
|
||||
}
|
||||
]
|
||||
|
||||
ext.gebDependencies = spockDependencies + [
|
||||
"org.seleniumhq.selenium:selenium-htmlunit-driver:$seleniumVersion",
|
||||
"org.gebish:geb-spock:$gebVersion",
|
||||
"org.codehaus.groovy:groovy:$groovyVersion"
|
||||
]
|
||||
|
||||
ext.jstlDependencies = [
|
||||
"javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:$jstlVersion",
|
||||
"org.apache.taglibs:taglibs-standard-jstlel:1.2.1"
|
||||
]
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://repo.spring.io/libs-snapshot' }
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
|
||||
if (details.requested.group == 'org.springframework') {
|
||||
details.useVersion springVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
// Integration test setup
|
||||
configurations {
|
||||
integrationTestCompile {
|
||||
extendsFrom testCompile, optional, provided
|
||||
}
|
||||
integrationTestRuntime {
|
||||
extendsFrom integrationTestCompile, testRuntime
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
integrationTest {
|
||||
java.srcDir file('src/integration-test/java')
|
||||
groovy.srcDirs file('src/integration-test/groovy')
|
||||
resources.srcDir file('src/integration-test/resources')
|
||||
compileClasspath = sourceSets.main.output + sourceSets.test.output + configurations.integrationTestCompile
|
||||
runtimeClasspath = output + compileClasspath + configurations.integrationTestRuntime
|
||||
}
|
||||
}
|
||||
|
||||
task integrationTest(type: Test, dependsOn: jar) {
|
||||
testClassesDir = sourceSets.integrationTest.output.classesDir
|
||||
logging.captureStandardOutput(LogLevel.INFO)
|
||||
classpath = sourceSets.integrationTest.runtimeClasspath
|
||||
maxParallelForks = 1
|
||||
reports {
|
||||
html.destination = project.file("$project.buildDir/reports/integration-tests/")
|
||||
junitXml.destination = project.file("$project.buildDir/integration-test-results/")
|
||||
}
|
||||
}
|
||||
check.dependsOn integrationTest
|
||||
|
||||
eclipse {
|
||||
classpath {
|
||||
plusConfigurations += [ configurations.integrationTestCompile ]
|
||||
}
|
||||
}
|
||||
|
||||
project.idea.module {
|
||||
scopes.TEST.plus += [project.configurations.integrationTestRuntime]
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
apply plugin: 'propdeps-maven'
|
||||
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
customizePom(pom, project)
|
||||
}
|
||||
}
|
||||
|
||||
def customizePom(pom, gradleProject) {
|
||||
pom.whenConfigured { generatedPom ->
|
||||
|
||||
// sort to make pom dependencies order consistent to ease comparison of older poms
|
||||
generatedPom.dependencies = generatedPom.dependencies.sort { dep ->
|
||||
"$dep.scope:$dep.groupId:$dep.artifactId"
|
||||
}
|
||||
|
||||
// add all items necessary for maven central publication
|
||||
generatedPom.project {
|
||||
name = gradleProject.description
|
||||
description = gradleProject.description
|
||||
url = "https://github.com/spring-projects/spring-session"
|
||||
organization {
|
||||
name = "Spring IO"
|
||||
url = "http://projects.spring.io/spring-session"
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name "The Apache Software License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
distribution "repo"
|
||||
}
|
||||
}
|
||||
scm {
|
||||
url = "https://github.com/spring-projects/spring-session"
|
||||
connection = "scm:git:git://github.com/spring-projects/spring-session"
|
||||
developerConnection = "scm:git:git://github.com/spring-projects/spring-session"
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = "rwinch"
|
||||
name = "Rob Winch"
|
||||
email = "rwinch@pivotal.io"
|
||||
}
|
||||
}
|
||||
issueManagement {
|
||||
system = "GitHub"
|
||||
url = "https://github.com/spring-projects/spring-session/issues"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
configurations {
|
||||
spring3TestRuntime.extendsFrom testRuntime
|
||||
}
|
||||
|
||||
configurations.spring3TestRuntime {
|
||||
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
|
||||
if (details.requested.group == 'org.springframework'
|
||||
&& details.requested.name != 'spring-websocket'
|
||||
&& details.requested.name != 'spring-messaging') {
|
||||
details.useVersion '3.2.14.RELEASE'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task spring3Test(type: Test) {
|
||||
jvmArgs = ['-ea', '-Xmx500m', '-XX:MaxPermSize=128M']
|
||||
classpath = sourceSets.test.output + sourceSets.main.output + configurations.spring3TestRuntime
|
||||
exclude "org/springframework/session/web/socket/**"
|
||||
reports {
|
||||
html.destination = project.file("$buildDir/spring3-test-results/")
|
||||
junitXml.destination = project.file("$buildDir/reports/spring3-tests/")
|
||||
}
|
||||
}
|
||||
check.dependsOn spring3Test
|
||||
@@ -1,64 +0,0 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url "https://repo.spring.io/plugins-release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:1.2.3")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'war'
|
||||
apply plugin: 'tomcat'
|
||||
|
||||
[tomcatRun,tomcatRunWar]*.contextPath = '/'
|
||||
|
||||
|
||||
task integrationTomcatRun(type: org.gradle.api.plugins.tomcat.tasks.TomcatRun) {
|
||||
onlyIf { !sourceSets.integrationTest.allSource.empty }
|
||||
buildscriptClasspath = tomcatRun.buildscriptClasspath
|
||||
contextPath = tomcatRun.contextPath
|
||||
daemon = true
|
||||
tomcatClasspath = tomcatRun.tomcatClasspath
|
||||
webAppClasspath = tomcatRun.webAppClasspath
|
||||
webAppSourceDirectory = tomcatRun.webAppSourceDirectory
|
||||
doFirst {
|
||||
def mainOutputDir = project.sourceSets.main.output.classesDir
|
||||
if(mainOutputDir) {
|
||||
classesDirectory = mainOutputDir
|
||||
}
|
||||
// delay reserving ports to ensure they are still available
|
||||
def ports = reservePorts(3)
|
||||
httpPort = ports[0]
|
||||
ajpPort = ports[1]
|
||||
stopPort = ports[2]
|
||||
|
||||
System.setProperty('spring.session.redis.namespace',project.name)
|
||||
}
|
||||
}
|
||||
|
||||
task integrationTomcatStop(type: org.gradle.api.plugins.tomcat.tasks.TomcatStop) {
|
||||
onlyIf { !sourceSets.integrationTest.allSource.empty }
|
||||
doFirst {
|
||||
stopPort = integrationTomcatRun.stopPort
|
||||
}
|
||||
}
|
||||
|
||||
integrationTest {
|
||||
dependsOn integrationTomcatRun
|
||||
doFirst {
|
||||
def host = 'localhost:' + integrationTomcatRun.httpPort
|
||||
systemProperties['geb.build.baseUrl'] = 'http://'+host+'/' + integrationTomcatRun.contextPath
|
||||
systemProperties['geb.build.reportsDir'] = 'build/geb-reports'
|
||||
}
|
||||
finalizedBy integrationTomcatStop
|
||||
}
|
||||
|
||||
def reservePorts(int count) {
|
||||
def sockets = []
|
||||
for(int i in 1..count) {
|
||||
sockets << new ServerSocket(0)
|
||||
}
|
||||
def result = sockets*.localPort
|
||||
sockets*.close()
|
||||
result
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
apply from: TOMCAT_GRADLE
|
||||
|
||||
dependencies {
|
||||
def tomcatVersion = '6.0.43'
|
||||
tomcat "org.apache.tomcat:catalina:${tomcatVersion}",
|
||||
"org.apache.tomcat:coyote:${tomcatVersion}",
|
||||
"org.apache.tomcat:jasper:${tomcatVersion}"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
apply from: TOMCAT_GRADLE
|
||||
|
||||
dependencies {
|
||||
def tomcatVersion = '7.0.59'
|
||||
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
|
||||
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
|
||||
tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
|
||||
exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj'
|
||||
}
|
||||
}
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,5 @@
|
||||
#Tue Nov 25 20:57:10 CST 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-rc-1-bin.zip
|
||||
|
||||
110
gradlew
vendored
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
@@ -6,47 +6,6 @@
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS="-Xmx1024M -XX:MaxPermSize=512M"
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
@@ -61,9 +20,49 @@ while [ -h "$PRG" ] ; do
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
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=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
@@ -90,7 +89,7 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
@@ -114,6 +113,7 @@ fi
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
@@ -154,11 +154,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 "$@")
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
# 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
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
14
gradlew.bat
vendored
@@ -8,14 +8,14 @@
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@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=-Xmx1024M -XX:MaxPermSize=512M
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
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=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
@@ -46,10 +46,9 @@ echo location of your Java installation.
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
@@ -60,11 +59,6 @@ set _SKIP=2
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
@@ -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".
|
||||
@@ -1,53 +0,0 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'spring-boot'
|
||||
|
||||
apply from: JAVA_GRADLE
|
||||
|
||||
tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
|
||||
group = 'samples'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session'),
|
||||
"org.springframework.boot:spring-boot-starter-redis",
|
||||
"org.springframework.boot:spring-boot-starter-web",
|
||||
"org.springframework.boot:spring-boot-starter-thymeleaf",
|
||||
"nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect",
|
||||
"org.springframework.security:spring-security-web:$springSecurityVersion",
|
||||
"org.springframework.security:spring-security-config:$springSecurityVersion"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
integrationTestCompile gebDependencies,
|
||||
"org.spockframework:spock-spring:$spockVersion"
|
||||
|
||||
}
|
||||
|
||||
integrationTest {
|
||||
doFirst {
|
||||
def port = reservePort()
|
||||
|
||||
def host = 'localhost:' + port
|
||||
systemProperties['geb.build.baseUrl'] = 'http://'+host+'/'
|
||||
systemProperties['geb.build.reportsDir'] = 'build/geb-reports'
|
||||
systemProperties['server.port'] = port
|
||||
systemProperties['management.port'] = 0
|
||||
|
||||
systemProperties['spring.session.redis.namespace'] = project.name
|
||||
}
|
||||
}
|
||||
|
||||
def reservePort() {
|
||||
def socket = new ServerSocket(0)
|
||||
def result = socket.localPort
|
||||
socket.close()
|
||||
result
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-boot'
|
||||
|
||||
dependencies {
|
||||
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-core"
|
||||
compile "com.maxmind.geoip2:geoip2"
|
||||
compile "org.apache.httpcomponents:httpclient"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
testCompile "org.assertj:assertj-core"
|
||||
|
||||
integrationTestCompile seleniumDependencies
|
||||
integrationTestCompile "org.testcontainers:testcontainers"
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.junit.After;
|
||||
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;
|
||||
|
||||
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.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
|
||||
|
||||
/**
|
||||
* @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:4.0.10";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
this.driver.quit();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void home() {
|
||||
LoginPage login = HomePage.go(this.driver);
|
||||
login.assertAt();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void login() {
|
||||
LoginPage login = HomePage.go(this.driver);
|
||||
HomePage home = login.form().login(HomePage.class);
|
||||
home.assertAt();
|
||||
home.containCookie("SESSION");
|
||||
home.doesNotContainCookie("JSESSIONID");
|
||||
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());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<SetCookieHandlerFilter> testFilter() {
|
||||
FilterRegistrationBean<SetCookieHandlerFilter> registrationBean = new FilterRegistrationBean<>(
|
||||
new SetCookieHandlerFilter());
|
||||
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SetCookieHandlerFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(
|
||||
httpServletResponse) {
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value) {
|
||||
if (HttpHeaders.SET_COOKIE.equals(name)) {
|
||||
List<HttpCookie> cookies = HttpCookie.parse(value);
|
||||
if (!cookies.isEmpty()) {
|
||||
addCookie(toServletCookie(cookies.get(0)));
|
||||
}
|
||||
}
|
||||
super.setHeader(name, value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
chain.doFilter(request, responseWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
private static Cookie toServletCookie(HttpCookie httpCookie) {
|
||||
Cookie cookie = new Cookie(httpCookie.getName(), httpCookie.getValue());
|
||||
String domain = httpCookie.getDomain();
|
||||
if (domain != null) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge());
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
cookie.setSecure(httpCookie.getSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
return cookie;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample.pages;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class BasePage {
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
public BasePage(WebDriver driver) {
|
||||
this.driver = driver;
|
||||
}
|
||||
|
||||
public WebDriver getDriver() {
|
||||
return this.driver;
|
||||
}
|
||||
|
||||
public static void get(WebDriver driver, String get) {
|
||||
String baseUrl = "http://localhost";
|
||||
driver.get(baseUrl + get);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample.pages;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.Set;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.Cookie;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.PageFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class HomePage extends BasePage {
|
||||
@FindBy(css = "input[type=\"submit\"]")
|
||||
WebElement logout;
|
||||
|
||||
public HomePage(WebDriver driver) {
|
||||
super(driver);
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle())
|
||||
.isEqualTo("Spring Session Sample - Secured Content");
|
||||
}
|
||||
|
||||
public void containCookie(String cookieName) {
|
||||
Set<Cookie> cookies = getDriver().manage().getCookies();
|
||||
assertThat(cookies).extracting("name").contains(cookieName);
|
||||
}
|
||||
|
||||
public void doesNotContainCookie(String cookieName) {
|
||||
Set<Cookie> cookies = getDriver().manage().getCookies();
|
||||
assertThat(cookies).extracting("name").doesNotContain(cookieName);
|
||||
}
|
||||
|
||||
public void terminateButtonDisabled() {
|
||||
Set<Cookie> cookies = getDriver().manage().getCookies();
|
||||
String cookieValue = null;
|
||||
for (Cookie cookie : cookies) {
|
||||
if ("SESSION".equals(cookie.getName())) {
|
||||
cookieValue = new String(Base64.getDecoder().decode(cookie.getValue()));
|
||||
}
|
||||
}
|
||||
WebElement element = getDriver().findElement(By.id("terminate-" + cookieValue));
|
||||
assertThat(element.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
public HomePage logout() {
|
||||
this.logout.click();
|
||||
return PageFactory.initElements(getDriver(), HomePage.class);
|
||||
}
|
||||
|
||||
public static LoginPage go(WebDriver driver) {
|
||||
get(driver, "/");
|
||||
return PageFactory.initElements(driver, LoginPage.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample.pages;
|
||||
|
||||
import org.openqa.selenium.SearchContext;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.PageFactory;
|
||||
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class LoginPage extends BasePage {
|
||||
|
||||
public LoginPage(WebDriver driver) {
|
||||
super(driver);
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Log In");
|
||||
}
|
||||
|
||||
public Form form() {
|
||||
return new Form(getDriver());
|
||||
}
|
||||
|
||||
public class Form {
|
||||
|
||||
@FindBy(name = "username")
|
||||
private WebElement username;
|
||||
|
||||
@FindBy(name = "password")
|
||||
private WebElement password;
|
||||
|
||||
@FindBy(tagName = "button")
|
||||
private WebElement button;
|
||||
|
||||
public Form(SearchContext context) {
|
||||
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
|
||||
}
|
||||
|
||||
public <T> T login(Class<T> page) {
|
||||
this.username.sendKeys("user");
|
||||
this.password.sendKeys("password");
|
||||
this.button.click();
|
||||
return PageFactory.initElements(getDriver(), page);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class FindByUsernameApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(FindByUsernameApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -13,16 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.config;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.maxmind.geoip2.DatabaseReader;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.maxmind.geoip2.DatabaseReader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
@@ -32,7 +33,9 @@ import com.maxmind.geoip2.DatabaseReader;
|
||||
public class GeoConfig {
|
||||
|
||||
@Bean
|
||||
public DatabaseReader geoDatabaseReader(@Value("classpath:GeoLite2-City.mmdb") InputStream geoInputStream) throws Exception {
|
||||
public DatabaseReader geoDatabaseReader(
|
||||
@Value("classpath:GeoLite2-City.mmdb") InputStream geoInputStream)
|
||||
throws Exception {
|
||||
return new DatabaseReader.Builder(geoInputStream).build();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
// end::config[]
|
||||
// @formatter:on
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/login").setViewName("login");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample.mvc;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Controller for sending the user to the login view.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
public class IndexController {
|
||||
// tag::findbyusername[]
|
||||
@Autowired
|
||||
FindByIndexNameSessionRepository<? extends Session> sessions;
|
||||
|
||||
@RequestMapping("/")
|
||||
public String index(Principal principal, Model model) {
|
||||
Collection<? extends Session> usersSessions = this.sessions
|
||||
.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
|
||||
principal.getName())
|
||||
.values();
|
||||
model.addAttribute("sessions", usersSessions);
|
||||
return "index";
|
||||
}
|
||||
// end::findbyusername[]
|
||||
|
||||
@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();
|
||||
if (usersSessionIds.contains(sessionIdToDelete)) {
|
||||
this.sessions.deleteById(sessionIdToDelete);
|
||||
}
|
||||
|
||||
return "redirect:/";
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -30,7 +31,7 @@ public class SessionDetails implements Serializable {
|
||||
private String accessType;
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
return this.location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
@@ -38,7 +39,7 @@ public class SessionDetails implements Serializable {
|
||||
}
|
||||
|
||||
public String getAccessType() {
|
||||
return accessType;
|
||||
return this.accessType;
|
||||
}
|
||||
|
||||
public void setAccessType(String accessType) {
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.session;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -24,20 +25,20 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import com.maxmind.geoip2.DatabaseReader;
|
||||
import com.maxmind.geoip2.model.CityResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import com.maxmind.geoip2.DatabaseReader;
|
||||
import com.maxmind.geoip2.model.CityResponse;
|
||||
|
||||
/**
|
||||
* Inserts the session details into the session for every request. Some users
|
||||
* may prefer to insert session details only after authentication. This is fine,
|
||||
* but it may be valuable to the most up to date information so that if someone
|
||||
* stole the user's session id it can be observed.
|
||||
* Inserts the session details into the session for every request. Some users may prefer
|
||||
* to insert session details only after authentication. This is fine, but it may be
|
||||
* valuable to the most up to date information so that if someone stole the user's session
|
||||
* id it can be observed.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
@@ -56,8 +57,9 @@ public class SessionDetailsFilter extends OncePerRequestFilter {
|
||||
}
|
||||
|
||||
// tag::dofilterinternal[]
|
||||
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
@Override
|
||||
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
chain.doFilter(request, response);
|
||||
|
||||
HttpSession session = request.getSession(false);
|
||||
@@ -76,18 +78,21 @@ public class SessionDetailsFilter extends OncePerRequestFilter {
|
||||
|
||||
String getGeoLocation(String remoteAddr) {
|
||||
try {
|
||||
CityResponse city = reader.city(InetAddress.getByName(remoteAddr));
|
||||
CityResponse city = this.reader.city(InetAddress.getByName(remoteAddr));
|
||||
String cityName = city.getCity().getName();
|
||||
String countryName = city.getCountry().getName();
|
||||
if(cityName == null && countryName == null) {
|
||||
if (cityName == null && countryName == null) {
|
||||
return null;
|
||||
} else if(cityName == null) {
|
||||
}
|
||||
else if (cityName == null) {
|
||||
return countryName;
|
||||
} else if(countryName == null) {
|
||||
}
|
||||
else if (countryName == null) {
|
||||
return cityName;
|
||||
}
|
||||
return cityName + ", " + countryName;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return UNKNOWN;
|
||||
|
||||
}
|
||||
@@ -97,11 +102,11 @@ public class SessionDetailsFilter extends OncePerRequestFilter {
|
||||
String remoteAddr = request.getHeader("X-FORWARDED-FOR");
|
||||
if (remoteAddr == null) {
|
||||
remoteAddr = request.getRemoteAddr();
|
||||
} else if (remoteAddr.contains(",")) {
|
||||
}
|
||||
else if (remoteAddr.contains(",")) {
|
||||
remoteAddr = remoteAddr.split(",")[0];
|
||||
}
|
||||
return remoteAddr;
|
||||
}
|
||||
}
|
||||
//end::class[]
|
||||
|
||||
// end::class[]
|
||||
|
Before Width: | Height: | Size: 30 MiB After Width: | Height: | Size: 30 MiB |
@@ -0,0 +1 @@
|
||||
spring.security.user.password=password
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,36 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Secured Content</title>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<h1>Secured Page</h1>
|
||||
<p>This page is secured using Spring Boot, Spring Session, and Spring Security.</p>
|
||||
|
||||
<p>Your current session id is <span id="session-id" th:text="${#httpSession.id}"></span></p>
|
||||
|
||||
<table class="table table-stripped">
|
||||
<tr>
|
||||
<th>Id Suffix</th>
|
||||
<th>Location</th>
|
||||
<th>Created</th>
|
||||
<th>Last Updated</th>
|
||||
<th>Information</th>
|
||||
<th>Terminate</th>
|
||||
</tr>
|
||||
<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="${#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">
|
||||
<input th:id="'terminate-' + ${sessionElement.id}" type="submit" value="Terminate" th:disabled="${sessionElement.id == #httpSession.id}"/>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,9 +3,9 @@
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/resources/img/favicon.ico}" href="../static/img/favicon.ico"/>
|
||||
<link th:href="@{/resources/css/bootstrap.css}" href="../static/css/bootstrap.css" rel="stylesheet"></link>
|
||||
<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"/>
|
||||
<link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet"></link>
|
||||
<style type="text/css">
|
||||
/* Sticky footer styles
|
||||
-------------------------------------------------- */
|
||||
@@ -65,11 +65,11 @@
|
||||
margin-left: 1em;
|
||||
}
|
||||
</style>
|
||||
<link th:href="@{resources/css/bootstrap-responsive.css}" href="/static/css/bootstrap-responsive.css" rel="stylesheet"></link>
|
||||
<link th:href="@{/webjars/bootstrap/css/bootstrap-responsive.min.css}" href="/webjars/bootstrap/css/bootstrap-responsive.min.css" rel="stylesheet"></link>
|
||||
|
||||
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<script th:src="@{/webjars/html5shiv/html5shiv.min.js}" src="/webjars/html5shiv/html5shiv.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<div class="navbar navbar-inverse navbar-static-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" th:href="@{/}"><img th:src="@{/resources/img/logo.png}" alt="Spring Security Sample"/></a>
|
||||
<a class="brand" th:href="@{/}"><img th:src="@{/images/logo.png}" alt="Spring Security Sample"/></a>
|
||||
|
||||
<div class="nav-collapse collapse"
|
||||
th:with="currentUser=${#httpServletRequest.userPrincipal?.principal}">
|
||||
@@ -119,4 +119,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,6 +1,6 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorator="layout">
|
||||
layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Log In</title>
|
||||
</head>
|
||||
@@ -44,4 +44,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -13,26 +13,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.session;
|
||||
|
||||
import static org.fest.assertions.Assertions.*;
|
||||
|
||||
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 com.maxmind.geoip2.DatabaseReader;
|
||||
|
||||
import sample.config.GeoConfig;
|
||||
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
|
||||
@@ -42,21 +42,24 @@ public class SessionDetailsFilterTests {
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
filter = new SessionDetailsFilter(reader);
|
||||
this.filter = new SessionDetailsFilter(this.reader);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getGeoLocationHanldesInvalidIp() {
|
||||
assertThat(filter.getGeoLocation("a")).isEqualTo(SessionDetailsFilter.UNKNOWN);
|
||||
assertThat(this.filter.getGeoLocation("a"))
|
||||
.isEqualTo(SessionDetailsFilter.UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getGeoLocationNullCity() {
|
||||
assertThat(filter.getGeoLocation("22.231.113.64")).isEqualTo("United States");
|
||||
assertThat(this.filter.getGeoLocation("22.231.113.64"))
|
||||
.isEqualTo("United States");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getGeoLocationBoth() {
|
||||
assertThat(filter.getGeoLocation("184.154.83.119")).isEqualTo("Chicago, United States");
|
||||
assertThat(this.filter.getGeoLocation("184.154.83.119"))
|
||||
.isEqualTo("Chicago, United States");
|
||||
}
|
||||
}
|
||||
}
|
||||
19
samples/boot/jdbc/spring-session-sample-boot-jdbc.gradle
Normal file
@@ -0,0 +1,19 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-boot'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-jdbc')
|
||||
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-devtools"
|
||||
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
|
||||
compile "org.webjars:bootstrap"
|
||||
compile "org.webjars:html5shiv"
|
||||
compile "org.webjars:webjars-locator-core"
|
||||
compile "com.h2database:h2"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
testCompile "org.assertj:assertj-core"
|
||||
|
||||
integrationTestCompile seleniumDependencies
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import sample.pages.HomePage;
|
||||
import sample.pages.LoginPage;
|
||||
|
||||
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.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@AutoConfigureMockMvc
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
|
||||
public class BootTests {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
this.driver.quit();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void home() {
|
||||
LoginPage login = HomePage.go(this.driver);
|
||||
login.assertAt();
|
||||
HomePage home = login.form().login(HomePage.class);
|
||||
home.assertAt();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void login() {
|
||||
LoginPage login = HomePage.go(this.driver);
|
||||
HomePage home = login.form().login(HomePage.class);
|
||||
home.containCookie("SESSION");
|
||||
home.doesNotContainCookie("JSESSIONID");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logout() {
|
||||
LoginPage login = HomePage.go(this.driver);
|
||||
HomePage home = login.form().login(HomePage.class);
|
||||
login = home.logout();
|
||||
login.assertAt();
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<SetCookieHandlerFilter> testFilter() {
|
||||
FilterRegistrationBean<SetCookieHandlerFilter> registrationBean = new FilterRegistrationBean<>(
|
||||
new SetCookieHandlerFilter());
|
||||
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SetCookieHandlerFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(
|
||||
httpServletResponse) {
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value) {
|
||||
if (HttpHeaders.SET_COOKIE.equals(name)) {
|
||||
List<HttpCookie> cookies = HttpCookie.parse(value);
|
||||
if (!cookies.isEmpty()) {
|
||||
addCookie(toServletCookie(cookies.get(0)));
|
||||
}
|
||||
}
|
||||
super.setHeader(name, value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
chain.doFilter(request, responseWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
private static Cookie toServletCookie(HttpCookie httpCookie) {
|
||||
Cookie cookie = new Cookie(httpCookie.getName(), httpCookie.getValue());
|
||||
String domain = httpCookie.getDomain();
|
||||
if (domain != null) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge());
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
cookie.setSecure(httpCookie.getSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
return cookie;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample.pages;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class BasePage {
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
public BasePage(WebDriver driver) {
|
||||
this.driver = driver;
|
||||
}
|
||||
|
||||
public WebDriver getDriver() {
|
||||
return this.driver;
|
||||
}
|
||||
|
||||
public static void get(WebDriver driver, String get) {
|
||||
String baseUrl = "http://localhost";
|
||||
driver.get(baseUrl + get);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample.pages;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.Cookie;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.PageFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class HomePage extends BasePage {
|
||||
|
||||
public HomePage(WebDriver driver) {
|
||||
super(driver);
|
||||
}
|
||||
|
||||
public static LoginPage go(WebDriver driver) {
|
||||
get(driver, "/");
|
||||
return PageFactory.initElements(driver, LoginPage.class);
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Secured Content");
|
||||
}
|
||||
|
||||
public void containCookie(String cookieName) {
|
||||
Set<Cookie> cookies = getDriver().manage().getCookies();
|
||||
assertThat(cookies).extracting("name").contains(cookieName);
|
||||
}
|
||||
|
||||
public void doesNotContainCookie(String cookieName) {
|
||||
Set<Cookie> cookies = getDriver().manage().getCookies();
|
||||
assertThat(cookies).extracting("name").doesNotContain(cookieName);
|
||||
}
|
||||
|
||||
public LoginPage logout() {
|
||||
WebElement logout = getDriver().findElement(By.cssSelector("input[type=\"submit\"]"));
|
||||
logout.click();
|
||||
return PageFactory.initElements(getDriver(), LoginPage.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample.pages;
|
||||
|
||||
import org.openqa.selenium.SearchContext;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.PageFactory;
|
||||
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class LoginPage extends BasePage {
|
||||
|
||||
public LoginPage(WebDriver driver) {
|
||||
super(driver);
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
|
||||
}
|
||||
|
||||
public Form form() {
|
||||
return new Form(getDriver());
|
||||
}
|
||||
|
||||
public class Form {
|
||||
|
||||
@FindBy(name = "username")
|
||||
private WebElement username;
|
||||
|
||||
@FindBy(name = "password")
|
||||
private WebElement password;
|
||||
|
||||
@FindBy(name = "submit")
|
||||
private WebElement button;
|
||||
|
||||
public Form(SearchContext context) {
|
||||
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
|
||||
}
|
||||
|
||||
public <T> T login(Class<T> page) {
|
||||
this.username.sendKeys("user");
|
||||
this.password.sendKeys("password");
|
||||
this.button.click();
|
||||
return PageFactory.initElements(getDriver(), page);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -13,20 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample.pages
|
||||
|
||||
import geb.Page
|
||||
package sample;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* The home page
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class HomePage extends Page {
|
||||
static url = ''
|
||||
static at = { assert driver.title == 'Secured Content'; true}
|
||||
static content = {
|
||||
username { $('#un').text() }
|
||||
logout(to:LoginPage) { $('input[type=submit]').click() }
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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
|
||||
*/
|
||||
@Configuration
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
// @formatter:off
|
||||
@Override
|
||||
public void configure(WebSecurity web) {
|
||||
web
|
||||
.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
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sample.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/").setViewName("index");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
spring.security.user.password=password
|
||||
spring.h2.console.enabled=true
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |