mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-08-30 05:07:10 +00:00
Compare commits
570 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
be64c67af5 | ||
|
a58f3282d9 | ||
|
c2ba662b91 | ||
|
49f308adb0 | ||
|
4cbe8de7ea | ||
|
559b73b39f | ||
|
3278f3a410 | ||
|
36f1de945f | ||
|
6663eea65f | ||
|
89b2f9cf54 | ||
|
0e39685b9c | ||
|
9d64880ea9 | ||
|
8b2a453301 | ||
|
d1962201b5 | ||
|
857ca9c412 | ||
|
894105aab5 | ||
|
f7f41ba6c4 | ||
|
f496ded4e5 | ||
|
583e668c6b | ||
|
d6a0e3bf78 | ||
|
29bb4919ca | ||
|
d9210c6596 | ||
|
b8b1a92ad4 | ||
|
bbcdb23698 | ||
|
9bbf837c7c | ||
|
8a1e2a22f9 | ||
|
0404996f87 | ||
|
0f63d98c84 | ||
|
fbfbb1e571 | ||
|
d002e68231 | ||
|
41162aa7e3 | ||
|
d86f2c957d | ||
|
62b5b1a77c | ||
|
523222c24d | ||
|
69f38d4933 | ||
|
0179a811c7 | ||
|
7ce2bdd701 | ||
|
de4ceffc4f | ||
|
8c920a7ee7 | ||
|
b9653346a1 | ||
|
9e6bcbd1d0 | ||
|
8d888edc71 | ||
|
f82fe9c8c6 | ||
|
a8f045eb50 | ||
|
5c5efc9092 | ||
|
5453224377 | ||
|
a14ad770ab | ||
|
806297da23 | ||
|
8846b44b81 | ||
|
7f103b2d0a | ||
|
c06ff59747 | ||
|
f1194de45e | ||
|
1f16009c8d | ||
|
3e13437b1a | ||
|
20a6863e07 | ||
|
e145c07d5b | ||
|
68a7f1702f | ||
|
3e8b606aac | ||
|
ef5c703010 | ||
|
47be93e694 | ||
|
9310153d16 | ||
|
a933089ec2 | ||
|
a8da9ec7f7 | ||
|
3396890d8b | ||
|
c45bc384da | ||
|
4da98dde2b | ||
|
7575e4ef1c | ||
|
70626fe3d9 | ||
|
acaed1ad96 | ||
|
0549bf566b | ||
|
01c8cea00f | ||
|
d2b70230f5 | ||
|
34aac5d45f | ||
|
319c7a4937 | ||
|
714781df78 | ||
|
a04b026000 | ||
|
aeb2dbc2b6 | ||
|
006f638c0a | ||
|
890c11d428 | ||
|
01401f1c67 | ||
|
6765ac0afa | ||
|
19c41054eb | ||
|
cbd51e8b36 | ||
|
bc7c72d6a3 | ||
|
39301574fa | ||
|
4ae782cdd6 | ||
|
f6f7cc6180 | ||
|
d3b143dab6 | ||
|
60c42e3f24 | ||
|
5506c487de | ||
|
2258699f5d | ||
|
7aaead5b02 | ||
|
e1341b22e0 | ||
|
40898775ec | ||
|
057b7c68fb | ||
|
7b1c917593 | ||
|
62ca6aaf21 | ||
|
dcd7490ddd | ||
|
08fa272749 | ||
|
164cc4611c | ||
|
4751d18761 | ||
|
4b3a0d28fe | ||
|
70d0422de2 | ||
|
bdcca0da52 | ||
|
df3080b0e2 | ||
|
a5c38bdc94 | ||
|
35b508adbf | ||
|
b4123a4570 | ||
|
4d1c5f20f8 | ||
|
fb41227c86 | ||
|
eee388adc6 | ||
|
989638d8d0 | ||
|
f334ee9128 | ||
|
1d2d268268 | ||
|
93204e81d5 | ||
|
cfe11bd15d | ||
|
57a9897840 | ||
|
acc9f84e67 | ||
|
eeb383ac46 | ||
|
6d1a886f92 | ||
|
6f1232ce79 | ||
|
93cb01612b | ||
|
dfc8be0d48 | ||
|
371bee685f | ||
|
5887f755a3 | ||
|
d0f5538f21 | ||
|
f61a8deccc | ||
|
d6e378e9bb | ||
|
bd98db4fe8 | ||
|
c9bf821402 | ||
|
ca557a9880 | ||
|
2fbe8dd8f6 | ||
|
1af665d6c8 | ||
|
1a56023f7f | ||
|
6873685fd0 | ||
|
0956846905 | ||
|
c84fd8a04b | ||
|
2866fa67ad | ||
|
b6ab504c64 | ||
|
9baee6fb14 | ||
|
99f689eb52 | ||
|
7bd7ff6b42 | ||
|
6c19a355b5 | ||
|
ae514b320f | ||
|
5e783abbe7 | ||
|
517a2b185f | ||
|
a2e85dd187 | ||
|
f6cb0bd610 | ||
|
4775fe41db | ||
|
116bee1303 | ||
|
bf877a9864 | ||
|
34742c9743 | ||
|
4ffec6dcdd | ||
|
c85aa61118 | ||
|
4503947faa | ||
|
d58b068098 | ||
|
6bdab77302 | ||
|
7f25f67dd0 | ||
|
9489ab48ab | ||
|
fe411896af | ||
|
176c3b8457 | ||
|
7e1a92b091 | ||
|
48533ede45 | ||
|
614763041e | ||
|
b672aae640 | ||
|
79cd982341 | ||
|
7c887d2da1 | ||
|
9db1ffbd79 | ||
|
bc4ec39fa5 | ||
|
fca30e3d25 | ||
|
84d54b94c9 | ||
|
02b922ce5a | ||
|
ef77d3f0cf | ||
|
85dc06bbdf | ||
|
4fa2d323fd | ||
|
f2886f0ffc | ||
|
23cf29ba17 | ||
|
63e0a56bee | ||
|
6fa82bc0e3 | ||
|
15fc898804 | ||
|
55a2100d1a | ||
|
2e75929856 | ||
|
ce6e8f9109 | ||
|
66ddfb43a0 | ||
|
b8741759ce | ||
|
eaaadefa18 | ||
|
a1f5b343ab | ||
|
25f69e92c7 | ||
|
a2d687f78b | ||
|
ecad58310a | ||
|
84dd6376a5 | ||
|
ad5ccf2a39 | ||
|
563163aab0 | ||
|
644c7ac821 | ||
|
aaa34af4f7 | ||
|
f96b9bb5cc | ||
|
b8796d84b7 | ||
|
f0c5a85d9a | ||
|
dadf4c0b8a | ||
|
5fefdd5bb3 | ||
|
0c42b61cc1 | ||
|
9df668151b | ||
|
4d3024cb49 | ||
|
686cc5fc1f | ||
|
684775b46a | ||
|
ff7359b54a | ||
|
ec16322000 | ||
|
b7ae9910b5 | ||
|
ee2b826362 | ||
|
7f8b9c895f | ||
|
728b5224cb | ||
|
f1725b25a0 | ||
|
2c87270dbc | ||
|
dadf10899c | ||
|
c312d18191 | ||
|
901b386ca6 | ||
|
da182a2d7c | ||
|
571b6fe4a8 | ||
|
9dea1c2eb5 | ||
|
c06b1f4916 | ||
|
e48fdd5ed4 | ||
|
dbb3b7e1f5 | ||
|
bfa2a3613c | ||
|
02d69ec864 | ||
|
a439bc65d6 | ||
|
19e88f5e35 | ||
|
242956a63c | ||
|
ca5e307bf4 | ||
|
8e94157971 | ||
|
e4155e8540 | ||
|
7aecd78920 | ||
|
e52987d03c | ||
|
62252c1232 | ||
|
a9636c72d1 | ||
|
74771a3d42 | ||
|
fdf52f021d | ||
|
6dc77bd98b | ||
|
42283a5c1d | ||
|
5ae1b73bae | ||
|
d8043dc8a7 | ||
|
21036c94b4 | ||
|
519ae241f4 | ||
|
596d44757a | ||
|
639a9afaea | ||
|
9312fb7004 | ||
|
448283b30c | ||
|
ce107795d8 | ||
|
af2985a269 | ||
|
d3e9e3138d | ||
|
b71a66bdaa | ||
|
e9506776f1 | ||
|
b6d61b2f10 | ||
|
919ae1d636 | ||
|
7da352129c | ||
|
558b7e0b47 | ||
|
e8ed0f1b03 | ||
|
3e53cc2c4a | ||
|
f709a9efef | ||
|
98686a5139 | ||
|
d869686d09 | ||
|
d5f986f733 | ||
|
f0d523b0ab | ||
|
1583c90433 | ||
|
a9e28a2ae9 | ||
|
8c100c5c27 | ||
|
4d524b1fe1 | ||
|
081c92a9e5 | ||
|
a22b2ffc94 | ||
|
06bd81b1da | ||
|
526f8a6200 | ||
|
edb7a642c7 | ||
|
dff5780e09 | ||
|
465d46caa1 | ||
|
f8cb1b77fa | ||
|
e869bcdfa3 | ||
|
cfe38957d7 | ||
|
ee171a1c17 | ||
|
eb468316fc | ||
|
eb3f32772f | ||
|
890049c6f7 | ||
|
75efb17c49 | ||
|
2e4259f359 | ||
|
7153d7930b | ||
|
d1aecb1ade | ||
|
4d9c81e3d1 | ||
|
eed4ae751e | ||
|
c43b128f1a | ||
|
f22f41ba19 | ||
|
3d9069ac4d | ||
|
a5b7bf989e | ||
|
3c5e6a32c2 | ||
|
725745defd | ||
|
25a5105b86 | ||
|
7704b4e986 | ||
|
1c6fb12dde | ||
|
f54c75f0f3 | ||
|
ff59dc35e9 | ||
|
2cccfe88a1 | ||
|
0cc49b8788 | ||
|
4ca80cdd28 | ||
|
a979094a48 | ||
|
3f9bb81164 | ||
|
0137d0254c | ||
|
f79c0bc734 | ||
|
d4c580ad49 | ||
|
418dc793ac | ||
|
a2f756264a | ||
|
20a486c83d | ||
|
08cdf7d53b | ||
|
8f0f3343fa | ||
|
91a5a97c50 | ||
|
a373ebd009 | ||
|
f34337a4e0 | ||
|
e37424c637 | ||
|
7587048f95 | ||
|
7de4217469 | ||
|
2f53a2edb3 | ||
|
e4a2ac27d6 | ||
|
401f836051 | ||
|
6798a0c2c4 | ||
|
a4012d60df | ||
|
7bf0cba45d | ||
|
f812a847df | ||
|
4f602cb1a5 | ||
|
4e6e25d3a5 | ||
|
feffe23a0e | ||
|
5dce2ab500 | ||
|
586340b2ae | ||
|
123ba5a81a | ||
|
00ead7f24d | ||
|
8fd2401a2e | ||
|
302d9a879f | ||
|
71cd14a165 | ||
|
f7d5390e74 | ||
|
f6f8417c11 | ||
|
cd14e3d161 | ||
|
e686ac6b11 | ||
|
a74ce06dae | ||
|
edfae34178 | ||
|
a8bd1d0143 | ||
|
054909694b | ||
|
fb6d29759c | ||
|
3fb987ed17 | ||
|
afb3d5d571 | ||
|
6ccadbd880 | ||
|
b4a447a99e | ||
|
8a0d746008 | ||
|
f04d5b9f05 | ||
|
14d9de2793 | ||
|
d26d76ecb3 | ||
|
3fd697f9a6 | ||
|
90ddb00c00 | ||
|
08cbdb4640 | ||
|
396809bf01 | ||
|
3e9d585410 | ||
|
a4c338f8a5 | ||
|
da6c7b8759 | ||
|
777447e1d9 | ||
|
cf6b52d6f7 | ||
|
5dd40a7f10 | ||
|
f789abc87f | ||
|
461f00ed38 | ||
|
9fcfacf283 | ||
|
1a7b1fcc7c | ||
|
45a1447e9b | ||
|
1435e0f3d3 | ||
|
13e738e733 | ||
|
c43afbf5e1 | ||
|
20a2213e11 | ||
|
09983e2349 | ||
|
6ddb964c61 | ||
|
349451c8a5 | ||
|
e17c256fce | ||
|
42e24aa53c | ||
|
06ed6ef342 | ||
|
676b44ebb0 | ||
|
ee09215f89 | ||
|
709f5db0e5 | ||
|
18010f9914 | ||
|
9cf5638914 | ||
|
c2c84c4243 | ||
|
b2325e4176 | ||
|
502b0b7f95 | ||
|
87bb5d4e2d | ||
|
df676b3089 | ||
|
fc587913a7 | ||
|
fce40bc3ed | ||
|
c2ecc8b538 | ||
|
bd31a40824 | ||
|
6036e1ceb5 | ||
|
f33b7b5479 | ||
|
32d0be9364 | ||
|
468a07b1a0 | ||
|
7da4712056 | ||
|
1f57df6caa | ||
|
5130cbb99f | ||
|
043464fd3d | ||
|
e1d8033ee3 | ||
|
8e57014c50 | ||
|
025995ef97 | ||
|
040ffe17e5 | ||
|
092bbfc8e7 | ||
|
b0cecb37d2 | ||
|
e3add59550 | ||
|
7bf2730a53 | ||
|
88ed4a5ccf | ||
|
2b740b7f1f | ||
|
f690a7f3df | ||
|
5f2efbea6a | ||
|
aba437d469 | ||
|
e8f920e0ee | ||
|
2bd05128ec | ||
|
e2e42a5580 | ||
|
16fd24c002 | ||
|
60f729156b | ||
|
220f49d86e | ||
|
9b724377ce | ||
|
02a8c416aa | ||
|
36c7b91fb9 | ||
|
ffd6e3c0f7 | ||
|
2c5bd4c916 | ||
|
dc954875f3 | ||
|
a060f7b462 | ||
|
d0db5e3ea3 | ||
|
aa3135169d | ||
|
3ddf201d66 | ||
|
edfd7b9b43 | ||
|
358f6c96b5 | ||
|
eaf8184142 | ||
|
097640b72a | ||
|
35e8aa6435 | ||
|
8e1db3fe2b | ||
|
28174a6d3e | ||
|
3948440ee4 | ||
|
72b5e96a0d | ||
|
a47022799e | ||
|
98c3453aa4 | ||
|
adca1b31be | ||
|
2e913d2af9 | ||
|
c8b843c4c5 | ||
|
eaab42a73c | ||
|
30577bd291 | ||
|
4967f3feee | ||
|
3f0326d3f1 | ||
|
0ec7a7a305 | ||
|
492444c588 | ||
|
f73f253beb | ||
|
32c7e8a6ee | ||
|
3de7312658 | ||
|
4ed131f6ab | ||
|
8953f464fb | ||
|
b20cfceabb | ||
|
9654e51bd4 | ||
|
d52e0b6a05 | ||
|
195f933438 | ||
|
ada75e76a6 | ||
|
227a2cc0c7 | ||
|
5517d8fe3a | ||
|
fd4f06a66e | ||
|
6d3b54df21 | ||
|
37a814bc29 | ||
|
215547f8c8 | ||
|
da2d9aa868 | ||
|
42790403da | ||
|
ec05e65668 | ||
|
bf05b8b430 | ||
|
91b21663db | ||
|
596449d882 | ||
|
1a4de49977 | ||
|
52394c1f07 | ||
|
fae61b9426 | ||
|
8612e952fe | ||
|
f4b8e2421a | ||
|
9ba5c7b2ce | ||
|
8e2067bb3e | ||
|
88369cd252 | ||
|
c9bbf3787b | ||
|
50f8ad55a8 | ||
|
64d3397a9c | ||
|
ff22866c6d | ||
|
cd27290260 | ||
|
e686621e92 | ||
|
d9c894fae8 | ||
|
47338f7e56 | ||
|
97923ebfaf | ||
|
c46f263483 | ||
|
b3340536dc | ||
|
07575d2e2e | ||
|
7e4c72806c | ||
|
0ee3fe2a58 | ||
|
45e81c2d0a | ||
|
b7909a56c5 | ||
|
a339dbc893 | ||
|
e772025646 | ||
|
e19c9995ae | ||
|
cc0faeaa9c | ||
|
33a0a12a20 | ||
|
2041757607 | ||
|
9004897e2d | ||
|
1cde8ca2c3 | ||
|
665a34da3a | ||
|
07a50b460a | ||
|
b5db32994f | ||
|
4fb3dca953 | ||
|
e30dc42d1e | ||
|
0722c2dc41 | ||
|
817938fa49 | ||
|
3b492a9628 | ||
|
c22091d8be | ||
|
aa4db57b89 | ||
|
903cefceb3 | ||
|
a8edcca961 | ||
|
a511171309 | ||
|
86550fb84b | ||
|
44303d2c80 | ||
|
462e38c0e3 | ||
|
8b925dc4fc | ||
|
3f91c3effc | ||
|
cb511f501a | ||
|
87434a7b05 | ||
|
f1e3f2a8d3 | ||
|
f511d0a345 | ||
|
64b26cbd1f | ||
|
99330bfc60 | ||
|
21c56554c9 | ||
|
c8339184a9 | ||
|
40a18fe63c | ||
|
0698d3527d | ||
|
93a7583aa4 | ||
|
a90ce5142c | ||
|
ba7be9c8b9 | ||
|
ff8b77df29 | ||
|
48eb243012 | ||
|
1e4dd713c5 | ||
|
6118587ff8 | ||
|
241c3cd35a | ||
|
693a5beb24 | ||
|
f13836c9c8 | ||
|
23e7c9eeaa | ||
|
d52289bd7a | ||
|
5eb232cd3d | ||
|
2b22cf2877 | ||
|
5f833fa236 | ||
|
7fda87aecd | ||
|
de622d1082 | ||
|
47f7d83ee4 | ||
|
69c52cc4f7 | ||
|
46ee6eda76 | ||
|
9c357984d7 | ||
|
e61544c397 | ||
|
506a801f29 | ||
|
866d8d0eab | ||
|
e599a17303 | ||
|
276bb82e7e | ||
|
a80592a707 | ||
|
b453840c0a | ||
|
e5e962ef90 | ||
|
0e2d864b09 | ||
|
607705347c | ||
|
66319fc3bc | ||
|
2dbf3a2d18 | ||
|
5704582c52 | ||
|
3976e7d456 | ||
|
b467c47ed5 | ||
|
11105a5c51 | ||
|
38a9aa1da9 | ||
|
222faae1cb | ||
|
cb0fdef236 | ||
|
5abbcecccc | ||
|
c385a59b68 |
78
.github/dependabot.yml
vendored
78
.github/dependabot.yml
vendored
@ -3,7 +3,37 @@ registries:
|
||||
spring-milestones:
|
||||
type: maven-repository
|
||||
url: https://repo.spring.io/milestone
|
||||
shibboleth:
|
||||
type: maven-repository
|
||||
url: https://build.shibboleth.net/maven/releases
|
||||
updates:
|
||||
- package-ecosystem: gradle
|
||||
target-branch: 6.5.x
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
time: '03:00'
|
||||
timezone: Etc/UTC
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
- dependency-name: org.python:jython
|
||||
- dependency-name: org.apache.directory.server:*
|
||||
- dependency-name: org.apache.directory.shared:*
|
||||
- dependency-name: org.junit:junit-bom
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- dependency-name: org.mockito:mockito-bom
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- dependency-name: '*'
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: gradle
|
||||
target-branch: 6.4.x
|
||||
directory: /
|
||||
@ -15,6 +45,7 @@ updates:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
- dependency-name: org.python:jython
|
||||
@ -30,32 +61,7 @@ updates:
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: gradle
|
||||
target-branch: 6.3.x
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
time: '03:00'
|
||||
timezone: Etc/UTC
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
- dependency-name: org.python:jython
|
||||
- dependency-name: org.apache.directory.server:*
|
||||
- dependency-name: org.apache.directory.shared:*
|
||||
- dependency-name: org.junit:junit-bom
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- dependency-name: org.mockito:mockito-bom
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- dependency-name: '*'
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
|
||||
- package-ecosystem: gradle
|
||||
target-branch: main
|
||||
directory: /
|
||||
@ -67,6 +73,7 @@ updates:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
- dependency-name: org.python:jython
|
||||
@ -87,25 +94,6 @@ updates:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
target-branch: 6.3.x
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'in: build'
|
||||
ignore:
|
||||
- dependency-name: sjohnr/*
|
||||
- package-ecosystem: github-actions
|
||||
target-branch: docs-build
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'in: build'
|
||||
|
||||
- package-ecosystem: npm
|
||||
target-branch: docs-build
|
||||
directory: /
|
||||
|
38
.github/workflows/check-snapshots.yml
vendored
Normal file
38
.github/workflows/check-snapshots.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
workflow_dispatch: # Manual trigger
|
||||
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
snapshot-test:
|
||||
name: Test Against Snapshots
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@v1
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- java-version: 21-ea
|
||||
toolchain: 21
|
||||
- java-version: 17
|
||||
toolchain: 17
|
||||
with:
|
||||
java-version: ${{ matrix.java-version }}
|
||||
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace
|
||||
secrets: inherit
|
||||
send-notification:
|
||||
name: Send Notification
|
||||
needs: [ snapshot-test ]
|
||||
if: ${{ !success() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Notification
|
||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
|
||||
with:
|
||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
@ -27,60 +27,24 @@ jobs:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
distribution: temurin
|
||||
secrets: inherit
|
||||
test:
|
||||
name: Test Against Snapshots
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@v1
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- java-version: 21-ea
|
||||
toolchain: 21
|
||||
- java-version: 17
|
||||
toolchain: 17
|
||||
with:
|
||||
java-version: ${{ matrix.java-version }}
|
||||
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=6.2.+ -PreactorVersion=2023.0.+ -PspringDataVersion=2024.0.+ --stacktrace
|
||||
secrets: inherit
|
||||
check-samples:
|
||||
name: Check Samples
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository_owner == 'spring-projects' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v2
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- name: Check samples project
|
||||
env:
|
||||
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
|
||||
SAMPLES_DIR: ../spring-security-samples
|
||||
run: |
|
||||
# Extract version from gradle.properties
|
||||
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
|
||||
# Extract samplesBranch from gradle.properties
|
||||
samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}')
|
||||
./gradlew publishMavenJavaPublicationToLocalRepository
|
||||
./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$samples_branch" -PcloneOutputDirectory="$SAMPLES_DIR"
|
||||
./gradlew --refresh-dependencies --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$version" test integrationTest
|
||||
deploy-artifacts:
|
||||
name: Deploy Artifacts
|
||||
needs: [ build, test, check-samples ]
|
||||
needs: [ build]
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@v1
|
||||
with:
|
||||
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
default-publish-milestones-central: true
|
||||
secrets: inherit
|
||||
deploy-docs:
|
||||
name: Deploy Docs
|
||||
needs: [ build, test, check-samples ]
|
||||
needs: [ build ]
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-docs.yml@v1
|
||||
with:
|
||||
should-deploy-docs: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
secrets: inherit
|
||||
deploy-schema:
|
||||
name: Deploy Schema
|
||||
needs: [ build, test, check-samples ]
|
||||
needs: [ build ]
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@v1
|
||||
with:
|
||||
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
@ -92,7 +56,7 @@ jobs:
|
||||
with:
|
||||
should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }}
|
||||
project-version: ${{ needs.deploy-artifacts.outputs.project-version }}
|
||||
milestone-repo-url: https://repo.spring.io/artifactory/milestone
|
||||
milestone-repo-url: https://repo1.maven.org/maven2
|
||||
release-repo-url: https://repo1.maven.org/maven2
|
||||
artifact-path: org/springframework/security/spring-security-core
|
||||
slack-announcing-id: spring-security-announcing
|
||||
|
2
.github/workflows/release-scheduler.yml
vendored
2
.github/workflows/release-scheduler.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
# List of active maintenance branches.
|
||||
branch: [ main, 6.4.x, 6.3.x ]
|
||||
branch: [ main, 6.5.x, 6.4.x, 6.3.x ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
@ -79,6 +79,9 @@ See https://github.com/spring-projects/spring-security/tree/main#building-from-s
|
||||
|
||||
The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize.
|
||||
|
||||
Additionally, since Streams are https://github.com/spring-projects/spring-security/issues/7154[much slower] than `for` loops, please use them judiciously.
|
||||
The team may ask you to change to a `for` loop if the given code is along a hot path.
|
||||
|
||||
To format the code as well as check the style, run `./gradlew format && ./gradlew check`.
|
||||
|
||||
[[submit-a-pull-request]]
|
||||
|
@ -1,5 +1,6 @@
|
||||
plugins {
|
||||
id "java-gradle-plugin"
|
||||
id "groovy-gradle-plugin"
|
||||
id "java"
|
||||
id "groovy"
|
||||
}
|
||||
@ -63,6 +64,7 @@ configurations {
|
||||
dependencies {
|
||||
implementation platform(libs.io.projectreactor.reactor.bom)
|
||||
|
||||
implementation libs.spring.nullability
|
||||
implementation libs.com.google.code.gson.gson
|
||||
implementation libs.com.thaiopensource.trag
|
||||
implementation libs.net.sourceforge.saxon.saxon
|
||||
@ -76,6 +78,7 @@ dependencies {
|
||||
implementation libs.com.github.spullara.mustache.java.compiler
|
||||
implementation libs.io.spring.javaformat.spring.javaformat.gradle.plugin
|
||||
implementation libs.io.spring.nohttp.nohttp.gradle
|
||||
implementation libs.org.jetbrains.kotlin.kotlin.gradle.plugin
|
||||
implementation (libs.net.sourceforge.htmlunit) {
|
||||
exclude group: 'org.eclipse.jetty.websocket', module: 'websocket-client'
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public class ManagementConfigurationPlugin implements Plugin<Project> {
|
||||
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
|
||||
publishing.getPublications().withType(MavenPublication.class, (mavenPublication -> {
|
||||
mavenPublication.versionMapping((versions) ->
|
||||
versions.allVariants(versionMapping -> versionMapping.fromResolutionResult())
|
||||
versions.allVariants((versionMapping) -> versionMapping.fromResolutionResult())
|
||||
);
|
||||
}));
|
||||
});
|
||||
|
@ -80,6 +80,11 @@ class RepositoryConventionPlugin implements Plugin<Project> {
|
||||
}
|
||||
url = 'https://repo.spring.io/release/'
|
||||
}
|
||||
forceMavenRepositories.findAll { it.startsWith('https://') || it.startsWith('file://') }.each { mavenUrl ->
|
||||
maven {
|
||||
url mavenUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,10 +32,13 @@ public class SchemaZipPlugin implements Plugin<Project> {
|
||||
for (def key : schemas.keySet()) {
|
||||
def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
|
||||
assert shortName != key
|
||||
def schemaResourceName = schemas.get(key)
|
||||
File xsdFile = module.sourceSets.main.resources.find {
|
||||
it.path.endsWith(schemas.get(key))
|
||||
it.path.endsWith(schemaResourceName)
|
||||
}
|
||||
if (xsdFile == null) {
|
||||
throw new IllegalStateException("Could not find schema file for resource name " + schemaResourceName + " in src/main/resources")
|
||||
}
|
||||
assert xsdFile != null
|
||||
schemaZip.into (shortName) {
|
||||
duplicatesStrategy 'exclude'
|
||||
from xsdFile.path
|
||||
|
17
buildSrc/src/main/groovy/security-kotlin.gradle
Normal file
17
buildSrc/src/main/groovy/security-kotlin.gradle
Normal file
@ -0,0 +1,17 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
id 'kotlin'
|
||||
}
|
||||
|
||||
project.plugins.withId("org.jetbrains.kotlin.jvm", (kotlinProject) -> {
|
||||
project.tasks.withType(KotlinCompile).configureEach {
|
||||
kotlinOptions {
|
||||
languageVersion = '2.2'
|
||||
apiVersion = '2.2'
|
||||
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
|
||||
jvmTarget = '17'
|
||||
|
||||
}
|
||||
}
|
||||
})
|
3
buildSrc/src/main/groovy/security-nullability.gradle
Normal file
3
buildSrc/src/main/groovy/security-nullability.gradle
Normal file
@ -0,0 +1,3 @@
|
||||
plugins {
|
||||
id 'io.spring.nullability'
|
||||
}
|
@ -81,9 +81,6 @@ public class CheckClasspathForProhibitedDependencies extends DefaultTask {
|
||||
if (group.startsWith("javax")) {
|
||||
return true;
|
||||
}
|
||||
if (group.equals("commons-logging")) {
|
||||
return true;
|
||||
}
|
||||
if (group.equals("org.slf4j") && id.getName().equals("jcl-over-slf4j")) {
|
||||
return true;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public class CheckExpectedBranchVersionPlugin implements Plugin<Project> {
|
||||
task.setDescription("Check if the project version matches the branch version");
|
||||
task.onlyIf("skipCheckExpectedBranchVersion property is false or not present", CheckExpectedBranchVersionPlugin::skipPropertyFalseOrNotPresent);
|
||||
task.getVersion().convention(project.provider(() -> project.getVersion().toString()));
|
||||
task.getBranchName().convention(project.getProviders().exec(execSpec -> execSpec.setCommandLine("git", "symbolic-ref", "--short", "HEAD")).getStandardOutput().getAsText());
|
||||
task.getBranchName().convention(project.getProviders().exec((execSpec) -> execSpec.setCommandLine("git", "symbolic-ref", "--short", "HEAD")).getStandardOutput().getAsText());
|
||||
task.getOutputFile().convention(project.getLayout().getBuildDirectory().file("check-expected-branch-version"));
|
||||
});
|
||||
project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> checkTask.dependsOn(checkExpectedBranchVersionTask));
|
||||
|
@ -17,8 +17,6 @@ package io.spring.gradle;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.gradle.testkit.runner.GradleRunner;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -23,8 +23,6 @@ import org.gradle.testfixtures.ProjectBuilder;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,6 @@ import org.apache.commons.io.FileUtils;
|
||||
import org.gradle.testkit.runner.BuildResult;
|
||||
import org.gradle.testkit.runner.TaskOutcome;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
|
@ -14,6 +14,7 @@ dependencies {
|
||||
|
||||
provided 'jakarta.servlet:jakarta.servlet-api'
|
||||
|
||||
testImplementation project(path : ':spring-security-web', configuration : 'tests')
|
||||
testImplementation "org.assertj:assertj-core"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params"
|
||||
|
@ -21,7 +21,6 @@ import java.util.ArrayList;
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
|
||||
/**
|
||||
* Temporary authentication object needed to load the user details service.
|
||||
@ -31,7 +30,7 @@ import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
*/
|
||||
public final class CasAssertionAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = 620L;
|
||||
|
||||
private final Assertion assertion;
|
||||
|
||||
|
@ -23,7 +23,6 @@ import org.apereo.cas.client.validation.Assertion;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@ -36,7 +35,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = 620L;
|
||||
|
||||
private final Object credentials;
|
||||
|
||||
|
@ -21,7 +21,6 @@ import java.util.Collection;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@ -38,7 +37,7 @@ public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationT
|
||||
static final String CAS_STATEFUL_IDENTIFIER = "_cas_stateful_";
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = 620L;
|
||||
|
||||
private final String identifier;
|
||||
|
||||
|
@ -34,7 +34,7 @@ import org.springframework.security.authentication.AuthenticationTrustResolverIm
|
||||
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken;
|
||||
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
|
||||
import org.springframework.security.cas.authentication.ServiceAuthenticationDetails;
|
||||
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@ -51,12 +51,12 @@ import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
|
||||
/**
|
||||
* Processes a CAS service ticket, obtains proxy granting tickets, and processes proxy
|
||||
* tickets.
|
||||
@ -216,7 +216,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
|
||||
public CasAuthenticationFilter() {
|
||||
super("/login/cas");
|
||||
RequestMatcher processUri = PathPatternRequestMatcher.withDefaults().matcher("/login/cas");
|
||||
RequestMatcher processUri = pathPattern("/login/cas");
|
||||
setRequiresAuthenticationRequestMatcher(processUri);
|
||||
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
|
||||
setSecurityContextRepository(this.securityContextRepository);
|
||||
@ -335,7 +335,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
}
|
||||
|
||||
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
|
||||
this.proxyReceptorMatcher = new AntPathRequestMatcher("/**" + proxyReceptorUrl);
|
||||
this.proxyReceptorMatcher = pathPattern(proxyReceptorUrl);
|
||||
}
|
||||
|
||||
public final void setProxyGrantingTicketStorage(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
|
||||
|
@ -22,6 +22,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.cas.authentication.ServiceAuthenticationDetails;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
import org.springframework.util.Assert;
|
||||
@ -60,7 +61,7 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
|
||||
/**
|
||||
* Returns the current URL minus the artifact parameter and its value, if present.
|
||||
* @see org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails#getServiceUrl()
|
||||
* @see org.springframework.security.cas.authentication.ServiceAuthenticationDetails#getServiceUrl()
|
||||
*/
|
||||
@Override
|
||||
public String getServiceUrl() {
|
||||
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web.authentication;
|
||||
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* In order for the
|
||||
* {@link org.springframework.security.cas.authentication.CasAuthenticationProvider} to
|
||||
* provide the correct service url to authenticate the ticket, the returned value of
|
||||
* {@link Authentication#getDetails()} should implement this interface when tickets can be
|
||||
* sent to any URL rather than only {@link ServiceProperties#getService()}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @see ServiceAuthenticationDetailsSource
|
||||
* @deprecated Please use
|
||||
* org.springframework.security.cas.authentication.ServiceAuthenticationDetails
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ServiceAuthenticationDetails
|
||||
extends org.springframework.security.cas.authentication.ServiceAuthenticationDetails {
|
||||
|
||||
/**
|
||||
* Gets the absolute service url (i.e. https://example.com/service/).
|
||||
* @return the service url. Cannot be <code>null</code>.
|
||||
*/
|
||||
String getServiceUrl();
|
||||
|
||||
}
|
@ -23,6 +23,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.authentication.ServiceAuthenticationDetails;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
@ -30,7 +30,6 @@ import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
|
@ -43,7 +43,6 @@ import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -55,6 +54,9 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.springframework.security.web.servlet.TestMockHttpServletRequests.get;
|
||||
import static org.springframework.security.web.servlet.TestMockHttpServletRequests.post;
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
|
||||
/**
|
||||
* Tests {@link CasAuthenticationFilter}.
|
||||
@ -79,9 +81,7 @@ public class CasAuthenticationFilterTests {
|
||||
|
||||
@Test
|
||||
public void testNormalOperation() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/login/cas");
|
||||
request.setServletPath("/login/cas");
|
||||
request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
|
||||
MockHttpServletRequest request = post("/login/cas").param("ticket", "ST-0-ER94xMJmn6pha35CQRoZ").build();
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setAuthenticationManager((a) -> a);
|
||||
assertThat(filter.requiresAuthentication(request, new MockHttpServletResponse())).isTrue();
|
||||
@ -104,24 +104,22 @@ public class CasAuthenticationFilterTests {
|
||||
String url = "/login/cas";
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setFilterProcessesUrl(url);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", url);
|
||||
MockHttpServletRequest request = post(url).build();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setServletPath(url);
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthenticationProxyRequest() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletRequest request = get("/pgtCallback").build();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setServletPath("/pgtCallback");
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
filter.setProxyReceptorUrl(request.getServletPath());
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
request.setServletPath("/other");
|
||||
request = get("/other").build();
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
}
|
||||
|
||||
@ -133,12 +131,10 @@ public class CasAuthenticationFilterTests {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setFilterProcessesUrl(url);
|
||||
filter.setServiceProperties(properties);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", url);
|
||||
MockHttpServletRequest request = post(url).build();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setServletPath(url);
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
request = new MockHttpServletRequest("POST", "/other");
|
||||
request.setServletPath("/other");
|
||||
request = post("/other").build();
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
request.setParameter(properties.getArtifactParameter(), "value");
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
@ -156,9 +152,8 @@ public class CasAuthenticationFilterTests {
|
||||
@Test
|
||||
public void testAuthenticateProxyUrl() throws Exception {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletRequest request = get("/pgtCallback").build();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setServletPath("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getServletPath());
|
||||
assertThat(filter.attemptAuthentication(request, response)).isNull();
|
||||
@ -172,9 +167,7 @@ public class CasAuthenticationFilterTests {
|
||||
given(manager.authenticate(any(Authentication.class))).willReturn(authentication);
|
||||
ServiceProperties serviceProperties = new ServiceProperties();
|
||||
serviceProperties.setAuthenticateAllArtifacts(true);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/authenticate");
|
||||
request.setParameter("ticket", "ST-1-123");
|
||||
request.setServletPath("/authenticate");
|
||||
MockHttpServletRequest request = post("/authenticate").param("ticket", "ST-1-123").build();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
@ -200,10 +193,9 @@ public class CasAuthenticationFilterTests {
|
||||
@Test
|
||||
public void testChainNotInvokedForProxyReceptor() throws Exception {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletRequest request = get("/pgtCallback").build();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
request.setServletPath("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getServletPath());
|
||||
filter.doFilter(request, response, chain);
|
||||
@ -271,16 +263,14 @@ public class CasAuthenticationFilterTests {
|
||||
@Test
|
||||
public void requiresAuthenticationWhenProxyRequestMatcherThenMatches() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/pgtCallback");
|
||||
MockHttpServletRequest request = get("/pgtCallback").build();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setServletPath("/pgtCallback");
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
filter.setProxyReceptorMatcher(PathPatternRequestMatcher.withDefaults().matcher(request.getServletPath()));
|
||||
filter.setProxyReceptorMatcher(pathPattern(request.getServletPath()));
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
request.setRequestURI("/other");
|
||||
request.setServletPath("/other");
|
||||
request = get("/other").build();
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.authentication.ServiceAuthenticationDetails;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -4,7 +4,7 @@ import trang.RncToXsd
|
||||
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'trang'
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'security-kotlin'
|
||||
|
||||
configurations {
|
||||
opensaml5 {
|
||||
@ -25,12 +25,12 @@ dependencies {
|
||||
optional project(':spring-security-ldap')
|
||||
optional project(':spring-security-messaging')
|
||||
optional project(path: ':spring-security-saml2-service-provider')
|
||||
opensaml5 project(path: ':spring-security-saml2-service-provider', configuration: 'opensamlFiveMain')
|
||||
optional project(':spring-security-oauth2-client')
|
||||
optional project(':spring-security-oauth2-jose')
|
||||
optional project(':spring-security-oauth2-resource-server')
|
||||
optional project(':spring-security-rsocket')
|
||||
optional project(':spring-security-web')
|
||||
optional project(':spring-security-webauthn')
|
||||
optional 'io.projectreactor:reactor-core'
|
||||
optional 'org.aspectj:aspectjweaver'
|
||||
optional 'org.springframework:spring-jdbc'
|
||||
@ -43,7 +43,6 @@ dependencies {
|
||||
optional 'org.jetbrains.kotlin:kotlin-reflect'
|
||||
optional 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
|
||||
optional 'jakarta.annotation:jakarta.annotation-api'
|
||||
optional libs.webauthn4j.core
|
||||
|
||||
provided 'jakarta.servlet:jakarta.servlet-api'
|
||||
|
||||
@ -57,6 +56,7 @@ dependencies {
|
||||
testImplementation project(':spring-security-saml2-service-provider')
|
||||
testImplementation project(path : ':spring-security-saml2-service-provider', configuration : 'tests')
|
||||
testImplementation project(path : ':spring-security-web', configuration : 'tests')
|
||||
testImplementation project(path : ':spring-security-webauthn', configuration : 'tests')
|
||||
testImplementation "jakarta.inject:jakarta.inject-api"
|
||||
testImplementation "org.assertj:assertj-core"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
@ -78,12 +78,6 @@ dependencies {
|
||||
exclude group: 'commons-logging', module: 'commons-logging'
|
||||
exclude group: 'xml-apis', module: 'xml-apis'
|
||||
}
|
||||
testImplementation "org.apache.directory.server:apacheds-core"
|
||||
testImplementation "org.apache.directory.server:apacheds-core-entry"
|
||||
testImplementation "org.apache.directory.server:apacheds-protocol-shared"
|
||||
testImplementation "org.apache.directory.server:apacheds-protocol-ldap"
|
||||
testImplementation "org.apache.directory.server:apacheds-server-jndi"
|
||||
testImplementation 'org.apache.directory.shared:shared-ldap'
|
||||
testImplementation "com.unboundid:unboundid-ldapsdk"
|
||||
testImplementation 'jakarta.persistence:jakarta.persistence-api'
|
||||
testImplementation "org.hibernate.orm:hibernate-core"
|
||||
@ -127,6 +121,7 @@ dependencies {
|
||||
|
||||
testRuntimeOnly 'org.hsqldb:hsqldb'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
|
||||
}
|
||||
|
||||
def rncToXsd = tasks.named('rncToXsd', RncToXsd)
|
||||
@ -158,15 +153,6 @@ tasks.named('sourcesJar', Jar).configure {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(KotlinCompile).configureEach {
|
||||
kotlinOptions {
|
||||
languageVersion = "1.7"
|
||||
apiVersion = "1.7"
|
||||
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
|
||||
configure(project.tasks.withType(Test)) {
|
||||
doFirst {
|
||||
systemProperties['springSecurityVersion'] = version
|
||||
@ -183,15 +169,3 @@ test {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("opensaml5Test", Test) {
|
||||
filter {
|
||||
includeTestsMatching "org.springframework.security.config.annotation.web.configurers.saml2.*"
|
||||
}
|
||||
useJUnitPlatform()
|
||||
classpath = sourceSets.main.output + sourceSets.test.output + configurations.opensaml5
|
||||
}
|
||||
|
||||
tasks.named("check") {
|
||||
dependsOn opensaml5Test
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@ -326,11 +326,11 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
|
||||
abstract static class BaseLdapServerConfig extends BaseLdapProviderConfig {
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapServer() throws Exception {
|
||||
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org",
|
||||
UnboundIdContainer ldapServer() throws Exception {
|
||||
UnboundIdContainer unboundIdContainer = new UnboundIdContainer("dc=springframework,dc=org",
|
||||
"classpath:/test-server.ldif");
|
||||
apacheDSContainer.setPort(getPort());
|
||||
return apacheDSContainer;
|
||||
unboundIdContainer.setPort(getPort());
|
||||
return unboundIdContainer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2004-present 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.rsocket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.rsocket.core.RSocketServer;
|
||||
import io.rsocket.exceptions.RejectedSetupException;
|
||||
import io.rsocket.frame.decoder.PayloadDecoder;
|
||||
import io.rsocket.transport.netty.server.CloseableChannel;
|
||||
import io.rsocket.transport.netty.server.TcpServerTransport;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.rsocket.RSocketRequester;
|
||||
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||
import org.springframework.security.rsocket.core.PayloadSocketAcceptorInterceptor;
|
||||
import org.springframework.security.rsocket.core.SecuritySocketAcceptorInterceptor;
|
||||
import org.springframework.security.rsocket.util.matcher.PayloadExchangeAuthorizationContext;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* @author Andrey Litvitski
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@ExtendWith(SpringExtension.class)
|
||||
public class AnonymousAuthenticationITests {
|
||||
|
||||
@Autowired
|
||||
RSocketMessageHandler handler;
|
||||
|
||||
@Autowired
|
||||
SecuritySocketAcceptorInterceptor interceptor;
|
||||
|
||||
@Autowired
|
||||
ServerController controller;
|
||||
|
||||
private CloseableChannel server;
|
||||
|
||||
private RSocketRequester requester;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
// @formatter:off
|
||||
this.server = RSocketServer.create()
|
||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||
)
|
||||
.acceptor(this.handler.responder())
|
||||
.bind(TcpServerTransport.create("localhost", 0))
|
||||
.block();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void dispose() {
|
||||
this.requester.rsocket().dispose();
|
||||
this.server.dispose();
|
||||
this.controller.payloads.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenAnonymousDisabledThenRespondsWithForbidden() {
|
||||
this.requester = RSocketRequester.builder()
|
||||
.rsocketStrategies(this.handler.getRSocketStrategies())
|
||||
.connectTcp("localhost", this.server.address().getPort())
|
||||
.block();
|
||||
String data = "andrew";
|
||||
assertThatExceptionOfType(RejectedSetupException.class).isThrownBy(
|
||||
() -> this.requester.route("secure.retrieve-mono").data(data).retrieveMono(String.class).block());
|
||||
assertThat(this.controller.payloads).isEmpty();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableRSocketSecurity
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
ServerController controller() {
|
||||
return new ServerController();
|
||||
}
|
||||
|
||||
@Bean
|
||||
RSocketMessageHandler messageHandler() {
|
||||
return new RSocketMessageHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
|
||||
AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
ReactiveAuthorizationManager<PayloadExchangeAuthorizationContext> anonymous = (authentication,
|
||||
exchange) -> authentication.map(trustResolver::isAnonymous).map(AuthorizationDecision::new);
|
||||
rsocket.authorizePayload((authorize) -> authorize.anyExchange().access(anonymous));
|
||||
rsocket.anonymous((anonymousAuthentication) -> anonymousAuthentication.disable());
|
||||
return rsocket.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Controller
|
||||
static class ServerController {
|
||||
|
||||
private List<String> payloads = new ArrayList<>();
|
||||
|
||||
@MessageMapping("**")
|
||||
String retrieveMono(String payload) {
|
||||
add(payload);
|
||||
return "Hi " + payload;
|
||||
}
|
||||
|
||||
private void add(String p) {
|
||||
this.payloads.add(p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -74,8 +74,7 @@ public class HelloRSocketITests {
|
||||
// @formatter:off
|
||||
this.server = RSocketServer.create()
|
||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||
.interceptors((registry) ->
|
||||
registry.forSocketAcceptor(this.interceptor)
|
||||
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||
)
|
||||
.acceptor(this.handler.responder())
|
||||
.bind(TcpServerTransport.create("localhost", 0))
|
||||
|
@ -87,8 +87,7 @@ public class HelloRSocketObservationITests {
|
||||
// @formatter:off
|
||||
this.server = RSocketServer.create()
|
||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||
.interceptors((registry) ->
|
||||
registry.forSocketAcceptor(this.interceptor)
|
||||
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||
)
|
||||
.acceptor(this.handler.responder())
|
||||
.bind(TcpServerTransport.create("localhost", 0))
|
||||
|
@ -74,8 +74,7 @@ public class HelloRSocketWithWebFluxITests {
|
||||
// @formatter:off
|
||||
this.server = RSocketServer.create()
|
||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||
.interceptors((registry) ->
|
||||
registry.forSocketAcceptor(this.interceptor)
|
||||
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||
)
|
||||
.acceptor(this.handler.responder())
|
||||
.bind(TcpServerTransport.create("localhost", 0))
|
||||
|
@ -86,8 +86,7 @@ public class JwtITests {
|
||||
// @formatter:off
|
||||
this.server = RSocketServer.create()
|
||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||
.interceptors((registry) ->
|
||||
registry.forSocketAcceptor(this.interceptor)
|
||||
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||
)
|
||||
.acceptor(this.handler.responder())
|
||||
.bind(TcpServerTransport.create("localhost", 0))
|
||||
|
@ -81,8 +81,7 @@ public class RSocketMessageHandlerConnectionITests {
|
||||
// @formatter:off
|
||||
this.server = RSocketServer.create()
|
||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||
.interceptors((registry) ->
|
||||
registry.forSocketAcceptor(this.interceptor)
|
||||
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||
)
|
||||
.acceptor(this.handler.responder())
|
||||
.bind(TcpServerTransport.create("localhost", 0))
|
||||
|
@ -79,8 +79,7 @@ public class RSocketMessageHandlerITests {
|
||||
// @formatter:off
|
||||
this.server = RSocketServer.create()
|
||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||
.interceptors((registry) ->
|
||||
registry.forSocketAcceptor(this.interceptor)
|
||||
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||
)
|
||||
.acceptor(this.handler.responder())
|
||||
.bind(TcpServerTransport.create("localhost", 0))
|
||||
|
@ -79,8 +79,7 @@ public class SimpleAuthenticationITests {
|
||||
// @formatter:off
|
||||
this.server = RSocketServer.create()
|
||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||
.interceptors((registry) ->
|
||||
registry.forSocketAcceptor(this.interceptor)
|
||||
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||
)
|
||||
.acceptor(this.handler.responder())
|
||||
.bind(TcpServerTransport.create("localhost", 0))
|
||||
|
@ -43,7 +43,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
|
||||
@ -226,18 +226,18 @@ public class LdapBindAuthenticationManagerFactoryITests {
|
||||
@EnableWebSecurity
|
||||
abstract static class BaseLdapServerConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
private UnboundIdContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapServer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
UnboundIdContainer ldapServer() {
|
||||
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
|
||||
int port = container.getLocalPort();
|
||||
BaseLdapPathContextSource contextSource(UnboundIdContainer container) {
|
||||
int port = container.getPort();
|
||||
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
@ -93,18 +93,18 @@ public class LdapPasswordComparisonAuthenticationManagerFactoryITests {
|
||||
@EnableWebSecurity
|
||||
abstract static class BaseLdapServerConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
private UnboundIdContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapServer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
UnboundIdContainer ldapServer() {
|
||||
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
|
||||
int port = container.getLocalPort();
|
||||
BaseLdapPathContextSource contextSource(UnboundIdContainer container) {
|
||||
int port = container.getPort();
|
||||
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||
AuthenticationManager.class);
|
||||
Authentication auth = authenticationManager
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("otherben", "otherbenspassword"));
|
||||
UserDetails ben = (UserDetails) auth.getPrincipal();
|
||||
assertThat(ben.getAuthorities()).hasSize(3);
|
||||
}
|
||||
@ -127,6 +127,27 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||
assertThat(auth).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsShaPasswordEncoder() {
|
||||
this.appCtx = new InMemoryXmlApplicationContext("""
|
||||
<ldap-server ldif='classpath:test-server.ldif' port='0'/>
|
||||
<authentication-manager>
|
||||
<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>
|
||||
<password-compare>
|
||||
<password-encoder ref='pe' />
|
||||
</password-compare>
|
||||
</ldap-authentication-provider>
|
||||
</authentication-manager>
|
||||
<b:bean id='pe' class='org.springframework.security.crypto.password.LdapShaPasswordEncoder' />
|
||||
""");
|
||||
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||
AuthenticationManager.class);
|
||||
Authentication auth = authenticationManager
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
|
||||
|
||||
assertThat(auth).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inetOrgContextMapperIsSupported() {
|
||||
this.appCtx = new InMemoryXmlApplicationContext(
|
||||
|
@ -26,7 +26,7 @@ import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -92,9 +92,9 @@ public class LdapServerBeanDefinitionParserTests {
|
||||
@Test
|
||||
public void defaultLdifFileIsSuccessful() {
|
||||
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server/>");
|
||||
ApacheDSContainer dsContainer = this.appCtx.getBean(ApacheDSContainer.class);
|
||||
UnboundIdContainer dsContainer = this.appCtx.getBean(UnboundIdContainer.class);
|
||||
|
||||
assertThat(ReflectionTestUtils.getField(dsContainer, "ldifResources")).isEqualTo("classpath*:*.ldif");
|
||||
assertThat(ReflectionTestUtils.getField(dsContainer, "ldif")).isEqualTo("classpath*:*.ldif");
|
||||
}
|
||||
|
||||
private int getDefaultPort() throws IOException {
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
<logger name="org.springframework.security" level="${sec.log.level:-WARN}"/>
|
||||
|
||||
<logger name="org.apache.directory" level="ERROR"/>
|
||||
<logger name="JdbmTable" level="INFO"/>
|
||||
<logger name="JdbmIndex" level="INFO"/>
|
||||
<logger name="org.apache.mina" level="WARN"/>
|
||||
|
@ -54,8 +54,6 @@ public abstract class BeanIds {
|
||||
|
||||
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor";
|
||||
|
||||
public static final String EMBEDDED_APACHE_DS = PREFIX + "apacheDirectoryServerContainer";
|
||||
|
||||
public static final String EMBEDDED_UNBOUNDID = PREFIX + "unboundidServerContainer";
|
||||
|
||||
public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource";
|
||||
|
@ -18,6 +18,7 @@ package org.springframework.security.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@ -77,26 +78,23 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
public SecurityNamespaceHandler() {
|
||||
String coreVersion = SpringSecurityCoreVersion.getVersion();
|
||||
String configVersion = configVersion();
|
||||
if (!Objects.equals(coreVersion, configVersion)) {
|
||||
String message = "You are attempting to run spring-security-core:%s with spring-security-config:%s";
|
||||
this.logger.error(String.format(message, coreVersion, configVersion));
|
||||
}
|
||||
}
|
||||
|
||||
private static String configVersion() {
|
||||
Package pkg = SpringSecurityCoreVersion.class.getPackage();
|
||||
if (pkg == null || coreVersion == null) {
|
||||
this.logger.info("Couldn't determine package version information.");
|
||||
return;
|
||||
}
|
||||
String version = pkg.getImplementationVersion();
|
||||
this.logger.info("Spring Security 'config' module version is " + version);
|
||||
if (version.compareTo(coreVersion) != 0) {
|
||||
this.logger
|
||||
.error("You are running with different versions of the Spring Security 'core' and 'config' modules");
|
||||
}
|
||||
return (pkg != null) ? pkg.getImplementationVersion() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
if (!namespaceMatchesVersion(element)) {
|
||||
pc.getReaderContext()
|
||||
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or "
|
||||
+ "spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
|
||||
+ "with Spring Security 6.5. Please update your schema declarations to the 6.5 schema.",
|
||||
.fatal("You cannot use any XSD older than spring-security-7.0.xsd. Either change to spring-security.xsd or spring-security-7.0.xsd",
|
||||
element);
|
||||
}
|
||||
String name = pc.getDelegate().getLocalName(element);
|
||||
@ -221,7 +219,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
private boolean matchesVersionInternal(Element element) {
|
||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||
return schemaLocation.matches("(?m).*spring-security-6\\.5.*.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-7\\.0.*.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2004-present 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config;
|
||||
|
||||
/**
|
||||
* A {@link Customizer} that allows invocation of code that throws a checked exception.
|
||||
*
|
||||
* @param <T> The type of input.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ThrowingCustomizer<T> extends Customizer<T> {
|
||||
|
||||
/**
|
||||
* Default {@link Customizer#customize(Object)} that wraps any thrown checked
|
||||
* exceptions (by default in a {@link RuntimeException}).
|
||||
* @param t the object to customize
|
||||
*/
|
||||
default void customize(T t) {
|
||||
try {
|
||||
customizeWithException(t);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the customization on the given object, possibly throwing a checked
|
||||
* exception.
|
||||
* @param t the object to customize
|
||||
* @throws Exception on error
|
||||
*/
|
||||
void customizeWithException(T t) throws Exception;
|
||||
|
||||
}
|
@ -80,15 +80,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
this(objectPostProcessor, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
protected AbstractConfiguredSecurityBuilder(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
this(objectPostProcessor, false);
|
||||
}
|
||||
|
||||
/***
|
||||
* Creates a new instance with the provided {@link ObjectPostProcessor}. This post
|
||||
* processor must support Object since there are many types of objects that may be
|
||||
@ -104,18 +95,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
this.allowConfigurersOfSameType = allowConfigurersOfSameType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
protected AbstractConfiguredSecurityBuilder(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<Object> objectPostProcessor,
|
||||
boolean allowConfigurersOfSameType) {
|
||||
Assert.notNull(objectPostProcessor, "objectPostProcessor cannot be null");
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
this.allowConfigurersOfSameType = allowConfigurersOfSameType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #build()} and {@link #getObject()} but checks the state to
|
||||
* determine if {@link #build()} needs to be called first.
|
||||
@ -135,24 +114,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a {@link SecurityConfigurerAdapter} to this {@link SecurityBuilder} and
|
||||
* invokes {@link SecurityConfigurerAdapter#setBuilder(SecurityBuilder)}.
|
||||
* @param configurer
|
||||
* @return the {@link SecurityConfigurerAdapter} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #with(SecurityConfigurerAdapter, Customizer)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer) throws Exception {
|
||||
configurer.addObjectPostProcessor(this.objectPostProcessor);
|
||||
configurer.setBuilder((B) this);
|
||||
add(configurer);
|
||||
return configurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a {@link SecurityConfigurer} to this {@link SecurityBuilder} overriding any
|
||||
* {@link SecurityConfigurer} of the exact same class. Note that object hierarchies
|
||||
@ -166,6 +127,28 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
return configurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a {@link SecurityConfigurerAdapter} to this {@link SecurityBuilder} and
|
||||
* invokes {@link SecurityConfigurerAdapter#setBuilder(SecurityBuilder)}.
|
||||
*
|
||||
* <p>
|
||||
* A shortcut for applying a configurer as-is, or in other words: <code>
|
||||
* .with(new MyConfigurer())
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* Is identical to: <code>
|
||||
* .with(new MyConfigurer(), Customizer.withDefaults())
|
||||
* </code>
|
||||
* @param configurer
|
||||
* @return the {@link SecurityBuilder} for further customizations
|
||||
* @throws Exception
|
||||
* @since 7.0
|
||||
*/
|
||||
public <C extends SecurityConfigurerAdapter<O, B>> B with(C configurer) throws Exception {
|
||||
return with(configurer, Customizer.withDefaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a {@link SecurityConfigurerAdapter} to this {@link SecurityBuilder} and
|
||||
* invokes {@link SecurityConfigurerAdapter#setBuilder(SecurityBuilder)}.
|
||||
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation;
|
||||
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Allows initialization of Objects. Typically this is used to call the {@link Aware}
|
||||
* methods, {@link InitializingBean#afterPropertiesSet()}, and ensure that
|
||||
* {@link DisposableBean#destroy()} has been invoked.
|
||||
*
|
||||
* @param <T> the bound of the types of Objects this {@link ObjectPostProcessor} supports.
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @deprecated please use {@link org.springframework.security.config.ObjectPostProcessor}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ObjectPostProcessor<T> extends org.springframework.security.config.ObjectPostProcessor<T> {
|
||||
|
||||
/**
|
||||
* Initialize the object possibly returning a modified instance that should be used
|
||||
* instead.
|
||||
* @param object the object to initialize
|
||||
* @return the initialized version of the object
|
||||
*/
|
||||
<O extends T> O postProcess(O object);
|
||||
|
||||
}
|
@ -21,6 +21,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@ -50,17 +51,6 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
|
||||
public void configure(B builder) throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link SecurityBuilder} when done using the {@link SecurityConfigurer}.
|
||||
* This is useful for method chaining.
|
||||
* @return the {@link SecurityBuilder} for further customizations
|
||||
* @deprecated For removal in 7.0. Use the lambda based configuration instead.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public B and() {
|
||||
return getBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link SecurityBuilder}. Cannot be null.
|
||||
* @return the {@link SecurityBuilder}
|
||||
@ -92,18 +82,9 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
|
||||
this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
public void addObjectPostProcessor(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<?> objectPostProcessor) {
|
||||
this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SecurityBuilder} to be used. This is automatically set when using
|
||||
* {@link AbstractConfiguredSecurityBuilder#apply(SecurityConfigurerAdapter)}
|
||||
* {@link AbstractConfiguredSecurityBuilder#with(SecurityConfigurerAdapter, Customizer)}
|
||||
* @param builder the {@link SecurityBuilder} to set
|
||||
*/
|
||||
public void setBuilder(B builder) {
|
||||
|
@ -73,15 +73,6 @@ public class AuthenticationManagerBuilder
|
||||
super(objectPostProcessor, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
public AuthenticationManagerBuilder(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
super(objectPostProcessor, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows providing a parent {@link AuthenticationManager} that will be tried if this
|
||||
* {@link AuthenticationManager} was unable to attempt to authenticate the provided
|
||||
@ -204,7 +195,9 @@ public class AuthenticationManagerBuilder
|
||||
* @throws Exception if an error occurs when adding the LDAP authentication
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthentication() throws Exception {
|
||||
return apply(new LdapAuthenticationProviderConfigurer<>());
|
||||
LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldap = new LdapAuthenticationProviderConfigurer<>();
|
||||
with(ldap);
|
||||
return ldap;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -286,7 +279,8 @@ public class AuthenticationManagerBuilder
|
||||
private <C extends UserDetailsAwareConfigurer<AuthenticationManagerBuilder, ? extends UserDetailsService>> C apply(
|
||||
C configurer) throws Exception {
|
||||
this.defaultUserDetailsService = configurer.getUserDetailsService();
|
||||
return super.apply(configurer);
|
||||
with(configurer);
|
||||
return configurer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
|
||||
|
||||
/**
|
||||
* The {@link EnableGlobalAuthentication} annotation signals that the annotated class can
|
||||
@ -87,14 +86,12 @@ import org.springframework.security.config.annotation.web.servlet.configuration.
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link EnableWebSecurity}</li>
|
||||
* <li>{@link EnableWebMvcSecurity}</li>
|
||||
* <li>{@link EnableGlobalMethodSecurity}</li>
|
||||
* </ul>
|
||||
*
|
||||
* Configuring {@link AuthenticationManagerBuilder} in a class without the
|
||||
* {@link EnableGlobalAuthentication} annotation has unpredictable results.
|
||||
*
|
||||
* @see EnableWebMvcSecurity
|
||||
* @see EnableWebSecurity
|
||||
* @see EnableGlobalMethodSecurity
|
||||
* @author Rob Winch
|
||||
|
@ -37,7 +37,6 @@ import org.springframework.security.ldap.authentication.LdapAuthenticator;
|
||||
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
|
||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||
import org.springframework.security.ldap.search.LdapUserSearch;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
|
||||
@ -60,12 +59,8 @@ import org.springframework.util.ClassUtils;
|
||||
public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuilder<B>>
|
||||
extends SecurityConfigurerAdapter<AuthenticationManager, B> {
|
||||
|
||||
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
|
||||
|
||||
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
||||
|
||||
private static final boolean apacheDsPresent;
|
||||
|
||||
private static final boolean unboundIdPresent;
|
||||
|
||||
private String groupRoleAttribute = "cn";
|
||||
@ -100,7 +95,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = LdapAuthenticationProviderConfigurer.class.getClassLoader();
|
||||
apacheDsPresent = ClassUtils.isPresent(APACHEDS_CLASSNAME, classLoader);
|
||||
unboundIdPresent = ClassUtils.isPresent(UNBOUNDID_CLASSNAME, classLoader);
|
||||
}
|
||||
|
||||
@ -139,16 +133,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
public LdapAuthenticationProviderConfigurer<B> withObjectPostProcessor(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link LdapAuthoritiesPopulator} and defaults to
|
||||
* {@link DefaultLdapAuthoritiesPopulator}
|
||||
@ -392,6 +376,10 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
return this;
|
||||
}
|
||||
|
||||
public B and() {
|
||||
return getBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B builder) throws Exception {
|
||||
LdapAuthenticationProvider provider = postProcess(build());
|
||||
@ -467,8 +455,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
*/
|
||||
public final class ContextSourceBuilder {
|
||||
|
||||
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
|
||||
|
||||
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
||||
|
||||
private static final int DEFAULT_PORT = 33389;
|
||||
@ -584,14 +570,8 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
private void startEmbeddedLdapServer() throws Exception {
|
||||
if (apacheDsPresent) {
|
||||
ApacheDSContainer apacheDsContainer = new ApacheDSContainer(this.root, this.ldif);
|
||||
apacheDsContainer.setPort(getPort());
|
||||
postProcess(apacheDsContainer);
|
||||
this.port = apacheDsContainer.getLocalPort();
|
||||
}
|
||||
else if (unboundIdPresent) {
|
||||
private void startEmbeddedLdapServer() {
|
||||
if (unboundIdPresent) {
|
||||
UnboundIdContainer unboundIdContainer = new UnboundIdContainer(this.root, this.ldif);
|
||||
unboundIdContainer.setPort(getPort());
|
||||
postProcess(unboundIdContainer);
|
||||
|
@ -41,4 +41,8 @@ public class InMemoryUserDetailsManagerConfigurer<B extends ProviderManagerBuild
|
||||
super(new InMemoryUserDetailsManager(new ArrayList<>()));
|
||||
}
|
||||
|
||||
public B and() {
|
||||
return getBuilder();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -63,17 +63,6 @@ public abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderMana
|
||||
return (C) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public C withObjectPostProcessor(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return (C) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying the {@link PasswordEncoder} to use with the
|
||||
* {@link DaoAuthenticationProvider}. The default is to use plain text.
|
||||
|
@ -16,13 +16,22 @@
|
||||
|
||||
package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
import org.springframework.data.geo.GeoPage;
|
||||
import org.springframework.data.geo.GeoResult;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.security.aot.hint.SecurityHintsRegistrar;
|
||||
import org.springframework.security.authorization.AuthorizationProxyFactory;
|
||||
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
|
||||
import org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ -34,4 +43,45 @@ final class AuthorizationProxyDataConfiguration implements AopInfrastructureBean
|
||||
return new AuthorizeReturnObjectDataHintsRegistrar(proxyFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
DataTargetVisitor dataTargetVisitor() {
|
||||
return new DataTargetVisitor();
|
||||
}
|
||||
|
||||
static final class DataTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor, Ordered {
|
||||
|
||||
private static final int DEFAULT_ORDER = 200;
|
||||
|
||||
@Override
|
||||
public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) {
|
||||
if (target instanceof GeoResults<?> geoResults) {
|
||||
return new GeoResults<>(proxyFactory.proxy(geoResults.getContent()), geoResults.getAverageDistance());
|
||||
}
|
||||
if (target instanceof GeoResult<?> geoResult) {
|
||||
return new GeoResult<>(proxyFactory.proxy(geoResult.getContent()), geoResult.getDistance());
|
||||
}
|
||||
if (target instanceof GeoPage<?> geoPage) {
|
||||
GeoResults<?> results = new GeoResults<>(proxyFactory.proxy(geoPage.getContent()),
|
||||
geoPage.getAverageDistance());
|
||||
return new GeoPage<>(results, geoPage.getPageable(), geoPage.getTotalElements());
|
||||
}
|
||||
if (target instanceof PageImpl<?> page) {
|
||||
List<?> content = proxyFactory.proxy(page.getContent());
|
||||
return new PageImpl<>(content, page.getPageable(), page.getTotalElements());
|
||||
}
|
||||
if (target instanceof SliceImpl<?> slice) {
|
||||
List<?> content = proxyFactory.proxy(slice.getContent());
|
||||
return new SliceImpl<>(content, slice.getPageable(), slice.hasNext());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,8 +16,12 @@
|
||||
|
||||
package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -25,12 +29,17 @@ import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
|
||||
import org.springframework.security.web.util.ThrowableAnalyzer;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.View;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
|
||||
|
||||
@Configuration
|
||||
class AuthorizationProxyWebConfiguration {
|
||||
class AuthorizationProxyWebConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
@ -38,6 +47,18 @@ class AuthorizationProxyWebConfiguration {
|
||||
return new WebTargetVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
|
||||
for (int i = 0; i < resolvers.size(); i++) {
|
||||
HandlerExceptionResolver resolver = resolvers.get(i);
|
||||
if (resolver instanceof DefaultHandlerExceptionResolver) {
|
||||
resolvers.add(i, new AccessDeniedExceptionResolver());
|
||||
return;
|
||||
}
|
||||
}
|
||||
resolvers.add(new AccessDeniedExceptionResolver());
|
||||
}
|
||||
|
||||
static class WebTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor, Ordered {
|
||||
|
||||
private static final int DEFAULT_ORDER = 100;
|
||||
@ -54,7 +75,7 @@ class AuthorizationProxyWebConfiguration {
|
||||
if (target instanceof ModelAndView mav) {
|
||||
View view = mav.getView();
|
||||
String viewName = mav.getViewName();
|
||||
Map<String, Object> model = (Map<String, Object>) proxyFactory.proxy(mav.getModel());
|
||||
Map<String, Object> model = proxyFactory.proxy(mav.getModel());
|
||||
ModelAndView proxied = (view != null) ? new ModelAndView(view, model)
|
||||
: new ModelAndView(viewName, model);
|
||||
proxied.setStatus(mav.getStatus());
|
||||
@ -70,4 +91,22 @@ class AuthorizationProxyWebConfiguration {
|
||||
|
||||
}
|
||||
|
||||
static class AccessDeniedExceptionResolver implements HandlerExceptionResolver {
|
||||
|
||||
final ThrowableAnalyzer throwableAnalyzer = new ThrowableAnalyzer();
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
Exception ex) {
|
||||
Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex);
|
||||
Throwable accessDeniedException = this.throwableAnalyzer
|
||||
.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
|
||||
if (accessDeniedException != null) {
|
||||
throw (AccessDeniedException) accessDeniedException;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,10 +20,10 @@ import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authorization.method.AuthorizationAdvisor;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
@ -40,7 +40,7 @@ final class DeferringMethodInterceptor<M extends AuthorizationAdvisor> implement
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
|
||||
public Object invoke(@NonNull MethodInvocation invocation) throws Throwable {
|
||||
return this.delegate.get().invoke(invocation);
|
||||
}
|
||||
|
||||
|
@ -407,16 +407,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware, SmartInit
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
@Autowired(required = false)
|
||||
public void setObjectPostProcessor(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setMethodSecurityExpressionHandler(List<MethodSecurityExpressionHandler> handlers) {
|
||||
if (handlers.size() != 1) {
|
||||
|
@ -19,8 +19,6 @@ package org.springframework.security.config.annotation.method.configuration;
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.Pointcut;
|
||||
@ -33,6 +31,8 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authorization.method.AuthorizationAdvisor;
|
||||
|
||||
class MethodSecurityAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
@ -100,7 +100,7 @@ class MethodSecurityAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
|
||||
public Object invoke(@NonNull MethodInvocation invocation) throws Throwable {
|
||||
return this.advisor.invoke(invocation);
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,6 @@ import org.springframework.security.authorization.method.PostAuthorizeAuthorizat
|
||||
import org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor;
|
||||
import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager;
|
||||
import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor;
|
||||
import org.springframework.security.authorization.method.PrePostTemplateDefaults;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
||||
@ -130,14 +129,6 @@ final class PrePostMethodSecurityConfiguration implements ImportAware, Applicati
|
||||
this.postFilterMethodInterceptor.setTemplateDefaults(templateDefaults);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
void setTemplateDefaults(PrePostTemplateDefaults templateDefaults) {
|
||||
this.preFilterMethodInterceptor.setTemplateDefaults(templateDefaults);
|
||||
this.preAuthorizeAuthorizationManager.setTemplateDefaults(templateDefaults);
|
||||
this.postAuthorizeAuthorizationManager.setTemplateDefaults(templateDefaults);
|
||||
this.postFilterMethodInterceptor.setTemplateDefaults(templateDefaults);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
|
||||
this.preFilterMethodInterceptor.setExpressionHandler(expressionHandler);
|
||||
|
@ -42,7 +42,6 @@ import org.springframework.security.authorization.method.PostAuthorizeReactiveAu
|
||||
import org.springframework.security.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor;
|
||||
import org.springframework.security.authorization.method.PreAuthorizeReactiveAuthorizationManager;
|
||||
import org.springframework.security.authorization.method.PreFilterAuthorizationReactiveMethodInterceptor;
|
||||
import org.springframework.security.authorization.method.PrePostTemplateDefaults;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
||||
@ -112,14 +111,6 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration
|
||||
this.postAuthorizeAuthorizationManager.setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
void setTemplateDefaults(PrePostTemplateDefaults templateDefaults) {
|
||||
this.preFilterMethodInterceptor.setTemplateDefaults(templateDefaults);
|
||||
this.preAuthorizeAuthorizationManager.setTemplateDefaults(templateDefaults);
|
||||
this.postAuthorizeAuthorizationManager.setTemplateDefaults(templateDefaults);
|
||||
this.postFilterMethodInterceptor.setTemplateDefaults(templateDefaults);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) {
|
||||
this.preFilterMethodInterceptor.setTemplateDefaults(templateDefaults);
|
||||
|
@ -109,6 +109,7 @@ import org.springframework.security.rsocket.util.matcher.RoutePayloadExchangeMat
|
||||
* @author Manuel Tejeda
|
||||
* @author Ebert Toribio
|
||||
* @author Ngoc Nhan
|
||||
* @author Andrey Litvitski
|
||||
* @since 5.2
|
||||
*/
|
||||
public class RSocketSecurity {
|
||||
@ -119,6 +120,8 @@ public class RSocketSecurity {
|
||||
|
||||
private SimpleAuthenticationSpec simpleAuthSpec;
|
||||
|
||||
private AnonymousAuthenticationSpec anonymousAuthSpec = new AnonymousAuthenticationSpec(this);
|
||||
|
||||
private JwtSpec jwtSpec;
|
||||
|
||||
private AuthorizePayloadsSpec authorizePayload;
|
||||
@ -164,6 +167,20 @@ public class RSocketSecurity {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds anonymous authentication
|
||||
* @param anonymous a customizer
|
||||
* @return this instance
|
||||
* @since 7.0
|
||||
*/
|
||||
public RSocketSecurity anonymous(Customizer<AnonymousAuthenticationSpec> anonymous) {
|
||||
if (this.anonymousAuthSpec == null) {
|
||||
this.anonymousAuthSpec = new AnonymousAuthenticationSpec(this);
|
||||
}
|
||||
anonymous.customize(this.anonymousAuthSpec);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds authentication with BasicAuthenticationPayloadExchangeConverter.
|
||||
* @param basic
|
||||
@ -214,7 +231,9 @@ public class RSocketSecurity {
|
||||
if (this.jwtSpec != null) {
|
||||
result.addAll(this.jwtSpec.build());
|
||||
}
|
||||
result.add(anonymous());
|
||||
if (this.anonymousAuthSpec != null) {
|
||||
result.add(this.anonymousAuthSpec.build());
|
||||
}
|
||||
if (this.authorizePayload != null) {
|
||||
result.add(this.authorizePayload.build());
|
||||
}
|
||||
@ -222,12 +241,6 @@ public class RSocketSecurity {
|
||||
return result;
|
||||
}
|
||||
|
||||
private AnonymousPayloadInterceptor anonymous() {
|
||||
AnonymousPayloadInterceptor result = new AnonymousPayloadInterceptor("anonymousUser");
|
||||
result.setOrder(PayloadInterceptorOrder.ANONYMOUS.getOrder());
|
||||
return result;
|
||||
}
|
||||
|
||||
private <T> T getBean(Class<T> beanClass) {
|
||||
if (this.context == null) {
|
||||
return null;
|
||||
@ -283,6 +296,26 @@ public class RSocketSecurity {
|
||||
|
||||
}
|
||||
|
||||
public final class AnonymousAuthenticationSpec {
|
||||
|
||||
private RSocketSecurity parent;
|
||||
|
||||
private AnonymousAuthenticationSpec(RSocketSecurity parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
protected AnonymousPayloadInterceptor build() {
|
||||
AnonymousPayloadInterceptor result = new AnonymousPayloadInterceptor("anonymousUser");
|
||||
result.setOrder(PayloadInterceptorOrder.ANONYMOUS.getOrder());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
this.parent.anonymousAuthSpec = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class BasicAuthenticationSpec {
|
||||
|
||||
private ReactiveAuthenticationManager authenticationManager;
|
||||
|
@ -18,41 +18,22 @@ package org.springframework.security.config.annotation.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.ServletRegistration;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.ServletRegistrationsSupport.RegistrationMapping;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
import org.springframework.util.function.ThrowingSupplier;
|
||||
|
||||
/**
|
||||
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for
|
||||
@ -65,25 +46,16 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
*/
|
||||
public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
|
||||
private static final boolean mvcPresent;
|
||||
|
||||
private static final RequestMatcher ANY_REQUEST = AnyRequestMatcher.INSTANCE;
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
private boolean anyRequestConfigured = false;
|
||||
|
||||
static {
|
||||
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
|
||||
AbstractRequestMatcherRegistry.class.getClassLoader());
|
||||
}
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private PathPatternRequestMatcher.Builder requestMatcherBuilder;
|
||||
|
||||
protected final void setApplicationContext(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
@ -107,36 +79,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
return configurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link MvcRequestMatcher} instances for the method and patterns passed in
|
||||
* @param method the HTTP method to use or null if any should be used
|
||||
* @param mvcPatterns the Spring MVC patterns to match on
|
||||
* @return a List of {@link MvcRequestMatcher} instances
|
||||
*/
|
||||
protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method, String... mvcPatterns) {
|
||||
Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest");
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class, Object.class);
|
||||
ObjectProvider<ObjectPostProcessor<Object>> postProcessors = this.context.getBeanProvider(type);
|
||||
ObjectPostProcessor<Object> opp = postProcessors.getObject();
|
||||
if (!this.context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
|
||||
throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME
|
||||
+ " of type " + HandlerMappingIntrospector.class.getName()
|
||||
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
|
||||
}
|
||||
HandlerMappingIntrospector introspector = this.context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
|
||||
HandlerMappingIntrospector.class);
|
||||
List<MvcRequestMatcher> matchers = new ArrayList<>(mvcPatterns.length);
|
||||
for (String mvcPattern : mvcPatterns) {
|
||||
MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern);
|
||||
opp.postProcess(matcher);
|
||||
if (method != null) {
|
||||
matcher.setMethod(method);
|
||||
}
|
||||
matchers.add(matcher);
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of
|
||||
* {@link org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher}
|
||||
@ -180,12 +122,9 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
|
||||
* {@link MvcRequestMatcher} that also specifies a specific {@link HttpMethod} to
|
||||
* match on. This matcher will use the same rules that Spring MVC uses for matching.
|
||||
* For example, often times a mapping of the path "/path" will match on "/path",
|
||||
* "/path/", "/path.html", etc. If the {@link HandlerMappingIntrospector} is not
|
||||
* available, maps to an {@link AntPathRequestMatcher}.
|
||||
* Match when the {@link HttpMethod} is {@code method} and when the request URI
|
||||
* matches one of {@code patterns}. See
|
||||
* {@link org.springframework.web.util.pattern.PathPattern} for matching rules.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a specific {@link RequestMatcher} must be specified, use
|
||||
@ -193,8 +132,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
* </p>
|
||||
* @param method the {@link HttpMethod} to use or {@code null} for any
|
||||
* {@link HttpMethod}.
|
||||
* @param patterns the patterns to match on. The rules for matching are defined by
|
||||
* Spring MVC if {@link MvcRequestMatcher} is used
|
||||
* @param patterns the patterns to match on
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}.
|
||||
* @since 5.8
|
||||
*/
|
||||
@ -205,31 +143,32 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
+ "leading slash in all your request matcher patterns. In future versions of "
|
||||
+ "Spring Security, leaving out the leading slash will result in an exception.");
|
||||
}
|
||||
if (!mvcPresent) {
|
||||
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
||||
}
|
||||
if (!(this.context instanceof WebApplicationContext)) {
|
||||
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
||||
}
|
||||
WebApplicationContext context = (WebApplicationContext) this.context;
|
||||
ServletContext servletContext = context.getServletContext();
|
||||
if (servletContext == null) {
|
||||
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
||||
}
|
||||
Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest");
|
||||
PathPatternRequestMatcher.Builder builder = getRequestMatcherBuilder();
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
for (String pattern : patterns) {
|
||||
if (RequestMatcherFactory.usesPathPatterns()) {
|
||||
matchers.add(RequestMatcherFactory.matcher(method, pattern));
|
||||
}
|
||||
else {
|
||||
AntPathRequestMatcher ant = new AntPathRequestMatcher(pattern, (method != null) ? method.name() : null);
|
||||
MvcRequestMatcher mvc = createMvcMatchers(method, pattern).get(0);
|
||||
matchers.add(new DeferredRequestMatcher((c) -> resolve(ant, mvc, c), mvc, ant));
|
||||
}
|
||||
matchers.add(builder.matcher(method, pattern));
|
||||
}
|
||||
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
|
||||
}
|
||||
|
||||
private PathPatternRequestMatcher.Builder getRequestMatcherBuilder() {
|
||||
if (this.requestMatcherBuilder != null) {
|
||||
return this.requestMatcherBuilder;
|
||||
}
|
||||
this.requestMatcherBuilder = this.context.getBeanProvider(PathPatternRequestMatcher.Builder.class)
|
||||
.getIfUnique(() -> constructRequestMatcherBuilder(this.context));
|
||||
return this.requestMatcherBuilder;
|
||||
}
|
||||
|
||||
private PathPatternRequestMatcher.Builder constructRequestMatcherBuilder(ApplicationContext context) {
|
||||
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder = new PathPatternRequestMatcherBuilderFactoryBean();
|
||||
requestMatcherBuilder.setApplicationContext(context);
|
||||
requestMatcherBuilder.setBeanFactory(context.getAutowireCapableBeanFactory());
|
||||
requestMatcherBuilder.setBeanName(requestMatcherBuilder.toString());
|
||||
return ThrowingSupplier.of(requestMatcherBuilder::getObject).get();
|
||||
}
|
||||
|
||||
private boolean anyPathsDontStartWithLeadingSlash(String... patterns) {
|
||||
for (String pattern : patterns) {
|
||||
if (!pattern.startsWith("/")) {
|
||||
@ -239,64 +178,16 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
return false;
|
||||
}
|
||||
|
||||
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
|
||||
ServletRegistrationsSupport registrations = new ServletRegistrationsSupport(servletContext);
|
||||
Collection<RegistrationMapping> mappings = registrations.mappings();
|
||||
if (mappings.isEmpty()) {
|
||||
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher());
|
||||
}
|
||||
Collection<RegistrationMapping> dispatcherServletMappings = registrations.dispatcherServletMappings();
|
||||
if (dispatcherServletMappings.isEmpty()) {
|
||||
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher());
|
||||
}
|
||||
if (dispatcherServletMappings.size() > 1) {
|
||||
String errorMessage = computeErrorMessage(servletContext.getServletRegistrations().values());
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
RegistrationMapping dispatcherServlet = dispatcherServletMappings.iterator().next();
|
||||
if (mappings.size() > 1 && !dispatcherServlet.isDefault()) {
|
||||
String errorMessage = computeErrorMessage(servletContext.getServletRegistrations().values());
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
if (dispatcherServlet.isDefault()) {
|
||||
if (mappings.size() == 1) {
|
||||
return mvc;
|
||||
}
|
||||
return new DispatcherServletDelegatingRequestMatcher(ant, mvc);
|
||||
}
|
||||
return mvc;
|
||||
}
|
||||
|
||||
private static String computeErrorMessage(Collection<? extends ServletRegistration> registrations) {
|
||||
String template = """
|
||||
This method cannot decide whether these patterns are Spring MVC patterns or not. \
|
||||
This is because there is more than one mappable servlet in your servlet context: %s.
|
||||
|
||||
To address this, please create one PathPatternRequestMatcher.Builder#servletPath for each servlet that has \
|
||||
authorized endpoints and use them to construct request matchers manually.
|
||||
""";
|
||||
Map<String, Collection<String>> mappings = new LinkedHashMap<>();
|
||||
for (ServletRegistration registration : registrations) {
|
||||
mappings.put(registration.getClassName(), registration.getMappings());
|
||||
}
|
||||
return String.format(template, mappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
|
||||
* {@link MvcRequestMatcher} that does not care which {@link HttpMethod} is used. This
|
||||
* matcher will use the same rules that Spring MVC uses for matching. For example,
|
||||
* often times a mapping of the path "/path" will match on "/path", "/path/",
|
||||
* "/path.html", etc. If the {@link HandlerMappingIntrospector} is not available, maps
|
||||
* to an {@link AntPathRequestMatcher}.
|
||||
* Match when the request URI matches one of {@code patterns}. See
|
||||
* {@link org.springframework.web.util.pattern.PathPattern} for matching rules.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a specific {@link RequestMatcher} must be specified, use
|
||||
* {@link #requestMatchers(RequestMatcher...)} instead
|
||||
* </p>
|
||||
* @param patterns the patterns to match on. The rules for matching are defined by
|
||||
* Spring MVC if {@link MvcRequestMatcher} is used
|
||||
* @param patterns the patterns to match on
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}.
|
||||
* @since 5.8
|
||||
*/
|
||||
@ -306,12 +197,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
|
||||
* {@link MvcRequestMatcher} that matches on a specific {@link HttpMethod}. This
|
||||
* matcher will use the same rules that Spring MVC uses for matching. For example,
|
||||
* often times a mapping of the path "/path" will match on "/path", "/path/",
|
||||
* "/path.html", etc. If the {@link HandlerMappingIntrospector} is not available, maps
|
||||
* to an {@link AntPathRequestMatcher}.
|
||||
* Match when the {@link HttpMethod} is {@code method}
|
||||
* </p>
|
||||
* <p>
|
||||
* If a specific {@link RequestMatcher} must be specified, use
|
||||
@ -335,182 +221,4 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
*/
|
||||
protected abstract C chainRequestMatchers(List<RequestMatcher> requestMatchers);
|
||||
|
||||
/**
|
||||
* Utilities for creating {@link RequestMatcher} instances.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
private static final class RequestMatchers {
|
||||
|
||||
private RequestMatchers() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link AntPathRequestMatcher} instances.
|
||||
* @param httpMethod the {@link HttpMethod} to use or {@code null} for any
|
||||
* {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create {@link AntPathRequestMatcher}
|
||||
* from
|
||||
* @return a {@link List} of {@link AntPathRequestMatcher} instances
|
||||
*/
|
||||
static List<RequestMatcher> antMatchers(HttpMethod httpMethod, String... antPatterns) {
|
||||
return Arrays.asList(antMatchersAsArray(httpMethod, antPatterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link AntPathRequestMatcher} instances that do not
|
||||
* specify an {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create {@link AntPathRequestMatcher}
|
||||
* from
|
||||
* @return a {@link List} of {@link AntPathRequestMatcher} instances
|
||||
*/
|
||||
static List<RequestMatcher> antMatchers(String... antPatterns) {
|
||||
return antMatchers(null, antPatterns);
|
||||
}
|
||||
|
||||
static RequestMatcher[] antMatchersAsArray(HttpMethod httpMethod, String... antPatterns) {
|
||||
String method = (httpMethod != null) ? httpMethod.toString() : null;
|
||||
RequestMatcher[] matchers = new RequestMatcher[antPatterns.length];
|
||||
for (int index = 0; index < antPatterns.length; index++) {
|
||||
matchers[index] = new AntPathRequestMatcher(antPatterns[index], method);
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link RegexRequestMatcher} instances.
|
||||
* @param httpMethod the {@link HttpMethod} to use or {@code null} for any
|
||||
* {@link HttpMethod}.
|
||||
* @param regexPatterns the regular expressions to create
|
||||
* {@link RegexRequestMatcher} from
|
||||
* @return a {@link List} of {@link RegexRequestMatcher} instances
|
||||
*/
|
||||
static List<RequestMatcher> regexMatchers(HttpMethod httpMethod, String... regexPatterns) {
|
||||
String method = (httpMethod != null) ? httpMethod.toString() : null;
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
for (String pattern : regexPatterns) {
|
||||
matchers.add(new RegexRequestMatcher(pattern, method));
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link RegexRequestMatcher} instances that do not
|
||||
* specify an {@link HttpMethod}.
|
||||
* @param regexPatterns the regular expressions to create
|
||||
* {@link RegexRequestMatcher} from
|
||||
* @return a {@link List} of {@link RegexRequestMatcher} instances
|
||||
*/
|
||||
static List<RequestMatcher> regexMatchers(String... regexPatterns) {
|
||||
return regexMatchers(null, regexPatterns);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DeferredRequestMatcher implements RequestMatcher {
|
||||
|
||||
final Function<ServletContext, RequestMatcher> requestMatcherFactory;
|
||||
|
||||
final AtomicReference<String> description = new AtomicReference<>();
|
||||
|
||||
final Map<ServletContext, RequestMatcher> requestMatchers = new ConcurrentHashMap<>();
|
||||
|
||||
DeferredRequestMatcher(Function<ServletContext, RequestMatcher> resolver, RequestMatcher... candidates) {
|
||||
this.requestMatcherFactory = (sc) -> this.requestMatchers.computeIfAbsent(sc, resolver);
|
||||
this.description.set("Deferred " + Arrays.toString(candidates));
|
||||
}
|
||||
|
||||
RequestMatcher requestMatcher(ServletContext servletContext) {
|
||||
return this.requestMatcherFactory.apply(servletContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
return this.requestMatcherFactory.apply(request.getServletContext()).matches(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchResult matcher(HttpServletRequest request) {
|
||||
return this.requestMatcherFactory.apply(request.getServletContext()).matcher(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.description.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MockMvcRequestMatcher implements RequestMatcher {
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
return request.getAttribute("org.springframework.test.web.servlet.MockMvc.MVC_RESULT_ATTRIBUTE") != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DispatcherServletRequestMatcher implements RequestMatcher {
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
String name = request.getHttpServletMapping().getServletName();
|
||||
ServletRegistration registration = request.getServletContext().getServletRegistration(name);
|
||||
Assert.notNull(registration,
|
||||
() -> computeErrorMessage(request.getServletContext().getServletRegistrations().values()));
|
||||
try {
|
||||
Class<?> clazz = Class.forName(registration.getClassName());
|
||||
return DispatcherServlet.class.isAssignableFrom(clazz);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DispatcherServletDelegatingRequestMatcher implements RequestMatcher {
|
||||
|
||||
private final AntPathRequestMatcher ant;
|
||||
|
||||
private final MvcRequestMatcher mvc;
|
||||
|
||||
private final RequestMatcher dispatcherServlet;
|
||||
|
||||
DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc) {
|
||||
this(ant, mvc, new OrRequestMatcher(new MockMvcRequestMatcher(), new DispatcherServletRequestMatcher()));
|
||||
}
|
||||
|
||||
DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc,
|
||||
RequestMatcher dispatcherServlet) {
|
||||
this.ant = ant;
|
||||
this.mvc = mvc;
|
||||
this.dispatcherServlet = dispatcherServlet;
|
||||
}
|
||||
|
||||
RequestMatcher requestMatcher(HttpServletRequest request) {
|
||||
if (this.dispatcherServlet.matches(request)) {
|
||||
return this.mvc;
|
||||
}
|
||||
return this.ant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
return requestMatcher(request).matches(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchResult matcher(HttpServletRequest request) {
|
||||
return requestMatcher(request).matcher(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DispatcherServletDelegating [" + "ant = " + this.ant + ", mvc = " + this.mvc + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
/**
|
||||
* This utility exists only to facilitate applications opting into using path patterns in
|
||||
* the HttpSecurity DSL. It is for internal use only.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public final class RequestMatcherFactory {
|
||||
|
||||
private static PathPatternRequestMatcher.Builder builder;
|
||||
|
||||
public static void setApplicationContext(ApplicationContext context) {
|
||||
builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class).getIfUnique();
|
||||
}
|
||||
|
||||
public static boolean usesPathPatterns() {
|
||||
return builder != null;
|
||||
}
|
||||
|
||||
public static RequestMatcher matcher(String path) {
|
||||
return matcher(null, path);
|
||||
}
|
||||
|
||||
public static RequestMatcher matcher(HttpMethod method, String path) {
|
||||
if (builder != null) {
|
||||
return builder.matcher(method, path);
|
||||
}
|
||||
return new AntPathRequestMatcher(path, (method != null) ? method.name() : null);
|
||||
}
|
||||
|
||||
private RequestMatcherFactory() {
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -55,6 +55,7 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer;
|
||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.PathPatternRequestTransformer;
|
||||
import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
@ -139,14 +140,6 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
super(objectPostProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
public WebSecurity(org.springframework.security.config.annotation.ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
super(objectPostProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Allows adding {@link RequestMatcher} instances that Spring Security should ignore.
|
||||
@ -430,7 +423,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
this.filterChainDecoratorPostProcessor = postProcessor.getIfUnique(ObjectPostProcessor::identity);
|
||||
Class<HttpServletRequestTransformer> requestTransformerClass = HttpServletRequestTransformer.class;
|
||||
this.privilegeEvaluatorRequestTransformer = applicationContext.getBeanProvider(requestTransformerClass)
|
||||
.getIfUnique();
|
||||
.getIfUnique(PathPatternRequestTransformer::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,11 +99,11 @@ final class WebSecurityFilterChainValidator implements FilterChainProxy.FilterCh
|
||||
}
|
||||
if (authorizationFilter != null && filterSecurityInterceptor != null) {
|
||||
this.logger.warn(
|
||||
"It is not recommended to use authorizeRequests in the configuration. Please only use authorizeHttpRequests");
|
||||
"It is not recommended to use authorizeRequests or FilterSecurityInterceptor in the configuration. Please only use authorizeHttpRequests");
|
||||
}
|
||||
if (filterSecurityInterceptor != null) {
|
||||
this.logger.warn(
|
||||
"Usage of authorizeRequests is deprecated. Please use authorizeHttpRequests in the configuration");
|
||||
"Usage of authorizeRequests and FilterSecurityInterceptor are deprecated. Please use authorizeHttpRequests in the configuration");
|
||||
}
|
||||
authorizationFilter = null;
|
||||
filterSecurityInterceptor = null;
|
||||
|
@ -46,8 +46,9 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
*
|
||||
* @Bean
|
||||
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
* http.authorizeHttpRequests().requestMatchers("/public/**").permitAll().anyRequest()
|
||||
* .hasRole("USER").and()
|
||||
* http.authorizeHttpRequests((authorize) -> authorize
|
||||
* .requestMatchers("/public/**").permitAll()
|
||||
* .anyRequest().hasRole("USER"))
|
||||
* // Possibly more configuration ...
|
||||
* .formLogin() // enable form based log in
|
||||
* // set permitAll for all URLs associated with Form Login
|
||||
|
@ -16,35 +16,43 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.JdbcUserDetailsManagerConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer;
|
||||
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.function.ThrowingSupplier;
|
||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
@ -105,7 +113,6 @@ class HttpSecurityConfiguration {
|
||||
@Bean(HTTPSECURITY_BEAN_NAME)
|
||||
@Scope("prototype")
|
||||
HttpSecurity httpSecurity() throws Exception {
|
||||
RequestMatcherFactory.setApplicationContext(this.context);
|
||||
LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
|
||||
AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(
|
||||
this.objectPostProcessor, passwordEncoder);
|
||||
@ -125,11 +132,13 @@ class HttpSecurityConfiguration {
|
||||
.requestCache(withDefaults())
|
||||
.anonymous(withDefaults())
|
||||
.servletApi(withDefaults())
|
||||
.apply(new DefaultLoginPageConfigurer<>());
|
||||
.with(new DefaultLoginPageConfigurer<>());
|
||||
http.logout(withDefaults());
|
||||
// @formatter:on
|
||||
applyCorsIfAvailable(http);
|
||||
applyDefaultConfigurers(http);
|
||||
applyHttpSecurityCustomizers(this.context, http);
|
||||
applyTopLevelCustomizers(this.context, http);
|
||||
return http;
|
||||
}
|
||||
|
||||
@ -155,17 +164,93 @@ class HttpSecurityConfiguration {
|
||||
List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
|
||||
.loadFactories(AbstractHttpConfigurer.class, classLoader);
|
||||
for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
|
||||
http.apply(configurer);
|
||||
http.with(configurer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all {@code Customizer<HttpSecurity>} Bean instances to the
|
||||
* {@link HttpSecurity} instance.
|
||||
* @param applicationContext the {@link ApplicationContext} to lookup Bean instances
|
||||
* @param http the {@link HttpSecurity} to apply the Beans to.
|
||||
*/
|
||||
private void applyHttpSecurityCustomizers(ApplicationContext applicationContext, HttpSecurity http) {
|
||||
ResolvableType httpSecurityCustomizerType = ResolvableType.forClassWithGenerics(Customizer.class,
|
||||
HttpSecurity.class);
|
||||
ObjectProvider<Customizer<HttpSecurity>> customizerProvider = this.context
|
||||
.getBeanProvider(httpSecurityCustomizerType);
|
||||
|
||||
// @formatter:off
|
||||
customizerProvider.orderedStream().forEach((customizer) ->
|
||||
customizer.customize(http)
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all {@link Customizer} Beans to {@link HttpSecurity}. For each public,
|
||||
* non-static method in HttpSecurity that accepts a Customizer
|
||||
* <ul>
|
||||
* <li>Use the {@link MethodParameter} (this preserves generics) to resolve all Beans
|
||||
* for that type</li>
|
||||
* <li>For each {@link Customizer} Bean invoke the {@link java.lang.reflect.Method}
|
||||
* with the {@link Customizer} Bean as the argument</li>
|
||||
* </ul>
|
||||
* @param context the {@link ApplicationContext}
|
||||
* @param http the {@link HttpSecurity}
|
||||
* @throws Exception
|
||||
*/
|
||||
private void applyTopLevelCustomizers(ApplicationContext context, HttpSecurity http) {
|
||||
ReflectionUtils.MethodFilter isCustomizerMethod = (method) -> {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
if (!Modifier.isPublic(method.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
if (!method.canAccess(http)) {
|
||||
return false;
|
||||
}
|
||||
if (method.getParameterCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (method.getParameterTypes()[0] == Customizer.class) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
ReflectionUtils.MethodCallback invokeWithEachCustomizerBean = (customizerMethod) -> {
|
||||
|
||||
MethodParameter customizerParameter = new MethodParameter(customizerMethod, 0);
|
||||
ResolvableType customizerType = ResolvableType.forMethodParameter(customizerParameter);
|
||||
ObjectProvider<?> customizerProvider = context.getBeanProvider(customizerType);
|
||||
|
||||
// @formatter:off
|
||||
customizerProvider.orderedStream().forEach((customizer) ->
|
||||
ReflectionUtils.invokeMethod(customizerMethod, http, customizer)
|
||||
);
|
||||
// @formatter:on
|
||||
|
||||
};
|
||||
ReflectionUtils.doWithMethods(HttpSecurity.class, invokeWithEachCustomizerBean, isCustomizerMethod);
|
||||
}
|
||||
|
||||
private Map<Class<?>, Object> createSharedObjects() {
|
||||
Map<Class<?>, Object> sharedObjects = new HashMap<>();
|
||||
sharedObjects.put(ApplicationContext.class, this.context);
|
||||
sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy);
|
||||
sharedObjects.put(PathPatternRequestMatcher.Builder.class, constructRequestMatcherBuilder(this.context));
|
||||
return sharedObjects;
|
||||
}
|
||||
|
||||
private PathPatternRequestMatcher.Builder constructRequestMatcherBuilder(ApplicationContext context) {
|
||||
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder = new PathPatternRequestMatcherBuilderFactoryBean();
|
||||
requestMatcherBuilder.setApplicationContext(context);
|
||||
requestMatcherBuilder.setBeanFactory(context.getAutowireCapableBeanFactory());
|
||||
requestMatcherBuilder.setBeanName(requestMatcherBuilder.toString());
|
||||
return ThrowingSupplier.of(requestMatcherBuilder::getObject).get();
|
||||
}
|
||||
|
||||
static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder {
|
||||
|
||||
private PasswordEncoder defaultPasswordEncoder;
|
||||
@ -180,17 +265,6 @@ class HttpSecurityConfiguration {
|
||||
this.defaultPasswordEncoder = defaultPasswordEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
DefaultPasswordEncoderAuthenticationManagerBuilder(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<Object> objectPostProcessor,
|
||||
PasswordEncoder defaultPasswordEncoder) {
|
||||
super(objectPostProcessor);
|
||||
this.defaultPasswordEncoder = defaultPasswordEncoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
|
||||
throws Exception {
|
||||
|
@ -50,13 +50,11 @@ import org.springframework.security.oauth2.client.DelegatingOAuth2AuthorizedClie
|
||||
import org.springframework.security.oauth2.client.JwtBearerOAuth2AuthorizedClientProvider;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
|
||||
import org.springframework.security.oauth2.client.PasswordOAuth2AuthorizedClientProvider;
|
||||
import org.springframework.security.oauth2.client.RefreshTokenOAuth2AuthorizedClientProvider;
|
||||
import org.springframework.security.oauth2.client.TokenExchangeOAuth2AuthorizedClientProvider;
|
||||
import org.springframework.security.oauth2.client.endpoint.JwtBearerGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2PasswordGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2RefreshTokenGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.TokenExchangeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
@ -173,7 +171,6 @@ final class OAuth2ClientConfiguration {
|
||||
AuthorizationCodeOAuth2AuthorizedClientProvider.class,
|
||||
RefreshTokenOAuth2AuthorizedClientProvider.class,
|
||||
ClientCredentialsOAuth2AuthorizedClientProvider.class,
|
||||
PasswordOAuth2AuthorizedClientProvider.class,
|
||||
JwtBearerOAuth2AuthorizedClientProvider.class,
|
||||
TokenExchangeOAuth2AuthorizedClientProvider.class
|
||||
);
|
||||
@ -241,7 +238,6 @@ final class OAuth2ClientConfiguration {
|
||||
authorizedClientProviders.add(getRefreshTokenAuthorizedClientProvider(authorizedClientProviderBeans));
|
||||
authorizedClientProviders
|
||||
.add(getClientCredentialsAuthorizedClientProvider(authorizedClientProviderBeans));
|
||||
authorizedClientProviders.add(getPasswordAuthorizedClientProvider(authorizedClientProviderBeans));
|
||||
|
||||
OAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider = getJwtBearerAuthorizedClientProvider(
|
||||
authorizedClientProviderBeans);
|
||||
@ -331,24 +327,6 @@ final class OAuth2ClientConfiguration {
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
private OAuth2AuthorizedClientProvider getPasswordAuthorizedClientProvider(
|
||||
Collection<OAuth2AuthorizedClientProvider> authorizedClientProviders) {
|
||||
PasswordOAuth2AuthorizedClientProvider authorizedClientProvider = getAuthorizedClientProviderByType(
|
||||
authorizedClientProviders, PasswordOAuth2AuthorizedClientProvider.class);
|
||||
if (authorizedClientProvider == null) {
|
||||
authorizedClientProvider = new PasswordOAuth2AuthorizedClientProvider();
|
||||
}
|
||||
|
||||
OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> accessTokenResponseClient = getBeanOfType(
|
||||
ResolvableType.forClassWithGenerics(OAuth2AccessTokenResponseClient.class,
|
||||
OAuth2PasswordGrantRequest.class));
|
||||
if (accessTokenResponseClient != null) {
|
||||
authorizedClientProvider.setAccessTokenResponseClient(accessTokenResponseClient);
|
||||
}
|
||||
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
private OAuth2AuthorizedClientProvider getJwtBearerAuthorizedClientProvider(
|
||||
Collection<OAuth2AuthorizedClientProvider> authorizedClientProviders) {
|
||||
JwtBearerOAuth2AuthorizedClientProvider authorizedClientProvider = getAuthorizedClientProviderByType(
|
||||
|
@ -26,15 +26,7 @@ import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@ -45,8 +37,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer;
|
||||
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
|
||||
import org.springframework.security.web.debug.DebugFilter;
|
||||
import org.springframework.security.web.firewall.HttpFirewall;
|
||||
import org.springframework.security.web.firewall.RequestRejectedHandler;
|
||||
@ -58,7 +48,6 @@ import org.springframework.web.filter.CompositeFilter;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
|
||||
/**
|
||||
@ -76,10 +65,6 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
*/
|
||||
class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContextAware {
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
|
||||
|
||||
private static final String PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME = "pathPatternRequestTransformer";
|
||||
|
||||
private BeanResolver beanResolver;
|
||||
|
||||
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
|
||||
@ -121,86 +106,6 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() {
|
||||
return new BeanDefinitionRegistryPostProcessor() {
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
if (!registry.containsBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String hmiRequestTransformerBeanName = HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer";
|
||||
if (!registry.containsBeanDefinition(PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME)
|
||||
&& !registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
|
||||
if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
|
||||
BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class)
|
||||
.addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)
|
||||
.getBeanDefinition();
|
||||
registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer);
|
||||
}
|
||||
}
|
||||
|
||||
BeanDefinition filterChainProxy = registry
|
||||
.getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
|
||||
|
||||
if (!filterChainProxy.getResolvableType().isInstance(CompositeFilterChainProxy.class)) {
|
||||
BeanDefinitionBuilder hmiCacheFilterBldr = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(HandlerMappingIntrospectorCacheFilterFactoryBean.class)
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
ManagedList<BeanMetadataElement> filters = new ManagedList<>();
|
||||
filters.add(hmiCacheFilterBldr.getBeanDefinition());
|
||||
filters.add(filterChainProxy);
|
||||
BeanDefinitionBuilder compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(CompositeFilterChainProxy.class)
|
||||
.addConstructorArgValue(filters);
|
||||
|
||||
registry.removeBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
|
||||
registry.registerBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME,
|
||||
compositeSpringSecurityFilterChainBldr.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} to defer creation of
|
||||
* {@link HandlerMappingIntrospector#createCacheFilter()}
|
||||
*
|
||||
* @deprecated see {@link WebSecurityConfiguration} for
|
||||
* {@link org.springframework.web.util.pattern.PathPattern} replacement
|
||||
*/
|
||||
@Deprecated
|
||||
static class HandlerMappingIntrospectorCacheFilterFactoryBean
|
||||
implements ApplicationContextAware, FactoryBean<Filter> {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter getObject() throws Exception {
|
||||
HandlerMappingIntrospector handlerMappingIntrospector = this.applicationContext
|
||||
.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector.class);
|
||||
return handlerMappingIntrospector.createCacheFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Filter.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends {@link FilterChainProxy} to provide as much passivity as possible but
|
||||
* delegates to {@link CompositeFilter} for
|
||||
|
@ -33,7 +33,6 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@ -69,7 +68,6 @@ import org.springframework.security.web.firewall.HttpFirewall;
|
||||
import org.springframework.security.web.firewall.RequestRejectedHandler;
|
||||
import org.springframework.web.filter.CompositeFilter;
|
||||
import org.springframework.web.filter.ServletRequestPathFilter;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
|
||||
@ -80,6 +78,7 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Keesun Baik
|
||||
* @author Yanming Zhou
|
||||
* @since 3.2
|
||||
* @see EnableWebSecurity
|
||||
* @see WebSecurity
|
||||
@ -191,7 +190,7 @@ public class WebSecurityConfiguration implements ImportAware {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static BeanFactoryPostProcessor conversionServicePostProcessor() {
|
||||
public static RsaKeyConversionServicePostProcessor conversionServicePostProcessor() {
|
||||
return new RsaKeyConversionServicePostProcessor();
|
||||
}
|
||||
|
||||
@ -209,12 +208,11 @@ public class WebSecurityConfiguration implements ImportAware {
|
||||
/**
|
||||
* Used to ensure Spring MVC request matching is cached.
|
||||
*
|
||||
* Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named
|
||||
* HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the
|
||||
* Creates a {@link BeanDefinitionRegistryPostProcessor} that moves the
|
||||
* AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name
|
||||
* and then adds a {@link CompositeFilter} that contains
|
||||
* {@link HandlerMappingIntrospector#createCacheFilter()} and the original
|
||||
* FilterChainProxy under the original Bean name.
|
||||
* {@link ServletRequestPathFilter} and the original FilterChainProxy under the
|
||||
* original Bean name.
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
|
@ -36,8 +36,6 @@ import org.springframework.util.Assert;
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see ChannelSecurityConfigurer
|
||||
* @see UrlAuthorizationConfigurer
|
||||
* @see ExpressionUrlAuthorizationConfigurer
|
||||
* @deprecated In modern Spring Security APIs, each API manages its own configuration
|
||||
* context. As such there is no direct replacement for this interface. In the case of
|
||||
* method security, please see {@link SecurityAnnotationScanner} and
|
||||
|
@ -25,6 +25,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
|
||||
/**
|
||||
* Adds a convenient base class for {@link SecurityConfigurer} instances that operate on
|
||||
@ -55,17 +56,6 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public T withObjectPostProcessor(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
protected SecurityContextHolderStrategy getSecurityContextHolderStrategy() {
|
||||
if (this.securityContextHolderStrategy != null) {
|
||||
return this.securityContextHolderStrategy;
|
||||
@ -76,4 +66,8 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
|
||||
return this.securityContextHolderStrategy;
|
||||
}
|
||||
|
||||
protected PathPatternRequestMatcher.Builder getRequestMatcherBuilder() {
|
||||
return getBuilder().getSharedObject(PathPatternRequestMatcher.Builder.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,196 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.vote.AffirmativeBased;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
|
||||
/**
|
||||
* A base class for configuring the {@link FilterSecurityInterceptor}.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are populated to allow other {@link SecurityConfigurer}'s
|
||||
* to customize:
|
||||
* <ul>
|
||||
* <li>{@link FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link AuthenticationManager}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <C> the AbstractInterceptUrlConfigurer
|
||||
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see ExpressionUrlAuthorizationConfigurer
|
||||
* @see UrlAuthorizationConfigurer
|
||||
* @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>, H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractHttpConfigurer<C, H> {
|
||||
|
||||
private Boolean filterSecurityInterceptorOncePerRequest;
|
||||
|
||||
private AccessDecisionManager accessDecisionManager;
|
||||
|
||||
AbstractInterceptUrlConfigurer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
|
||||
if (metadataSource == null) {
|
||||
return;
|
||||
}
|
||||
FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(http, metadataSource,
|
||||
http.getSharedObject(AuthenticationManager.class));
|
||||
if (this.filterSecurityInterceptorOncePerRequest != null) {
|
||||
securityInterceptor.setObserveOncePerRequest(this.filterSecurityInterceptorOncePerRequest);
|
||||
}
|
||||
securityInterceptor = postProcess(securityInterceptor);
|
||||
http.addFilter(securityInterceptor);
|
||||
http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should implement this method to provide a
|
||||
* {@link FilterInvocationSecurityMetadataSource} for the
|
||||
* {@link FilterSecurityInterceptor}.
|
||||
* @param http the builder to use
|
||||
* @return the {@link FilterInvocationSecurityMetadataSource} to set on the
|
||||
* {@link FilterSecurityInterceptor}. Cannot be null.
|
||||
*/
|
||||
abstract FilterInvocationSecurityMetadataSource createMetadataSource(H http);
|
||||
|
||||
/**
|
||||
* Subclasses should implement this method to provide the {@link AccessDecisionVoter}
|
||||
* instances used to create the default {@link AccessDecisionManager}
|
||||
* @param http the builder to use
|
||||
* @return the {@link AccessDecisionVoter} instances used to create the default
|
||||
* {@link AccessDecisionManager}
|
||||
*/
|
||||
abstract List<AccessDecisionVoter<?>> getDecisionVoters(H http);
|
||||
|
||||
/**
|
||||
* Creates the default {@code AccessDecisionManager}
|
||||
* @return the default {@code AccessDecisionManager}
|
||||
*/
|
||||
private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
|
||||
AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));
|
||||
return postProcess(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* If currently null, creates a default {@link AccessDecisionManager} using
|
||||
* {@link #createDefaultAccessDecisionManager(HttpSecurityBuilder)}. Otherwise returns
|
||||
* the {@link AccessDecisionManager}.
|
||||
* @param http the builder to use
|
||||
* @return the {@link AccessDecisionManager} to use
|
||||
*/
|
||||
private AccessDecisionManager getAccessDecisionManager(H http) {
|
||||
if (this.accessDecisionManager == null) {
|
||||
this.accessDecisionManager = createDefaultAccessDecisionManager(http);
|
||||
}
|
||||
return this.accessDecisionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link FilterSecurityInterceptor}
|
||||
* @param http the builder to use
|
||||
* @param metadataSource the {@link FilterInvocationSecurityMetadataSource} to use
|
||||
* @param authenticationManager the {@link AuthenticationManager} to use
|
||||
* @return the {@link FilterSecurityInterceptor}
|
||||
* @throws Exception
|
||||
*/
|
||||
private FilterSecurityInterceptor createFilterSecurityInterceptor(H http,
|
||||
FilterInvocationSecurityMetadataSource metadataSource, AuthenticationManager authenticationManager)
|
||||
throws Exception {
|
||||
FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
|
||||
securityInterceptor.setSecurityMetadataSource(metadataSource);
|
||||
securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http));
|
||||
securityInterceptor.setAuthenticationManager(authenticationManager);
|
||||
securityInterceptor.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
securityInterceptor.afterPropertiesSet();
|
||||
return securityInterceptor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R, T>, T>
|
||||
extends AbstractConfigAttributeRequestMatcherRegistry<T> {
|
||||
|
||||
AbstractInterceptUrlRegistry() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows setting the {@link AccessDecisionManager}. If none is provided, a
|
||||
* default {@link AccessDecisionManager} is created.
|
||||
* @param accessDecisionManager the {@link AccessDecisionManager} to use
|
||||
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
|
||||
*/
|
||||
public R accessDecisionManager(AccessDecisionManager accessDecisionManager) {
|
||||
AbstractInterceptUrlConfigurer.this.accessDecisionManager = accessDecisionManager;
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows setting if the {@link FilterSecurityInterceptor} should be only applied
|
||||
* once per request (i.e. if the filter intercepts on a forward, should it be
|
||||
* applied again).
|
||||
* @param filterSecurityInterceptorOncePerRequest if the
|
||||
* {@link FilterSecurityInterceptor} should be only applied once per request
|
||||
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
|
||||
*/
|
||||
public R filterSecurityInterceptorOncePerRequest(boolean filterSecurityInterceptorOncePerRequest) {
|
||||
AbstractInterceptUrlConfigurer.this.filterSecurityInterceptorOncePerRequest = filterSecurityInterceptorOncePerRequest;
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the current object with a single suppression of the type
|
||||
* @return a reference to the current object
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private R getSelf() {
|
||||
return (R) this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -21,6 +21,7 @@ import java.util.UUID;
|
||||
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
@ -57,7 +58,7 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#anonymous()
|
||||
* @see HttpSecurity#anonymous(Customizer)
|
||||
*/
|
||||
public AnonymousConfigurer() {
|
||||
}
|
||||
|
@ -110,7 +110,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
AuthorizationManager<HttpServletRequest> authorizationManager = this.registry.createAuthorizationManager();
|
||||
AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
|
||||
authorizationFilter.setAuthorizationEventPublisher(this.publisher);
|
||||
authorizationFilter.setShouldFilterAllDispatcherTypes(this.registry.shouldFilterAllDispatcherTypes);
|
||||
authorizationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
http.addFilter(postProcess(authorizationFilter));
|
||||
}
|
||||
@ -144,8 +143,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
|
||||
private int mappingCount;
|
||||
|
||||
private boolean shouldFilterAllDispatcherTypes = true;
|
||||
|
||||
private AuthorizationManagerRequestMatcherRegistry(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
@ -191,57 +188,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
public AuthorizationManagerRequestMatcherRegistry withObjectPostProcessor(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether all dispatcher types should be filtered.
|
||||
* @param shouldFilter should filter all dispatcher types. Default is {@code true}
|
||||
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
|
||||
* customizations
|
||||
* @since 5.7
|
||||
* @deprecated Permit access to the {@link jakarta.servlet.DispatcherType}
|
||||
* instead. <pre>
|
||||
* @Configuration
|
||||
* @EnableWebSecurity
|
||||
* public class SecurityConfig {
|
||||
*
|
||||
* @Bean
|
||||
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
* http
|
||||
* .authorizeHttpRequests((authorize) -> authorize
|
||||
* .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
|
||||
* // ...
|
||||
* );
|
||||
* return http.build();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AuthorizationManagerRequestMatcherRegistry shouldFilterAllDispatcherTypes(boolean shouldFilter) {
|
||||
this.shouldFilterAllDispatcherTypes = shouldFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link HttpSecurityBuilder} when done using the
|
||||
* {@link AuthorizeHttpRequestsConfigurer}. This is useful for method chaining.
|
||||
* @return the {@link HttpSecurityBuilder} for further customizations
|
||||
* @deprecated For removal in 7.0. Use the lambda based configuration instead.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public H and() {
|
||||
return AuthorizeHttpRequestsConfigurer.this.and();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,10 +24,7 @@ import java.util.List;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
@ -96,7 +93,7 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#requiresChannel()
|
||||
* @see HttpSecurity#requiresChannel(Customizer)
|
||||
*/
|
||||
public ChannelSecurityConfigurer(ApplicationContext context) {
|
||||
this.REGISTRY = new ChannelRequestMatcherRegistry(context);
|
||||
@ -175,16 +172,6 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
public ChannelRequestMatcherRegistry withObjectPostProcessor(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ChannelProcessor} instances to use in
|
||||
* {@link ChannelDecisionManagerImpl}
|
||||
@ -207,18 +194,6 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link SecurityBuilder} when done using the
|
||||
* {@link SecurityConfigurer}. This is useful for method chaining.
|
||||
* @return the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link HttpSecurity#requiresChannel(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public H and() {
|
||||
return ChannelSecurityConfigurer.this.and();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,21 +18,18 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* Adds {@link CorsFilter} to the Spring Security filter chain. If a bean by the name of
|
||||
* corsFilter is provided, that {@link CorsFilter} is used. Else if
|
||||
* corsConfigurationSource is defined, then that {@link CorsConfiguration} is used.
|
||||
* Otherwise, if Spring MVC is on the classpath a {@link HandlerMappingIntrospector} is
|
||||
* used.
|
||||
*
|
||||
* @param <H> the builder to return.
|
||||
* @author Rob Winch
|
||||
@ -44,20 +41,12 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHt
|
||||
|
||||
private static final String CORS_FILTER_BEAN_NAME = "corsFilter";
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
|
||||
private static final boolean mvcPresent;
|
||||
|
||||
private CorsConfigurationSource configurationSource;
|
||||
|
||||
static {
|
||||
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, CorsConfigurer.class.getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @see HttpSecurity#cors()
|
||||
* @see HttpSecurity#cors(Customizer)
|
||||
*/
|
||||
public CorsConfigurer() {
|
||||
}
|
||||
@ -90,10 +79,7 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHt
|
||||
CorsConfigurationSource.class);
|
||||
return new CorsFilter(configurationSource);
|
||||
}
|
||||
if (mvcPresent) {
|
||||
return MvcCorsFilter.getMvcCorsFilter(context);
|
||||
}
|
||||
return null;
|
||||
return MvcCorsFilter.getMvcCorsFilter(context);
|
||||
}
|
||||
|
||||
static class MvcCorsFilter {
|
||||
|
@ -19,12 +19,15 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
@ -34,13 +37,17 @@ import org.springframework.security.web.access.CompositeAccessDeniedHandler;
|
||||
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
||||
import org.springframework.security.web.access.ObservationMarkingAccessDeniedHandler;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
||||
import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
|
||||
import org.springframework.security.web.csrf.CsrfFilter;
|
||||
import org.springframework.security.web.csrf.CsrfLogoutHandler;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
||||
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
|
||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||
import org.springframework.security.web.csrf.MissingCsrfTokenException;
|
||||
import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler;
|
||||
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
|
||||
import org.springframework.security.web.session.InvalidSessionStrategy;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
@ -48,6 +55,7 @@ import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Adds
|
||||
@ -96,7 +104,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#csrf()
|
||||
* @see HttpSecurity#csrf(Customizer)
|
||||
*/
|
||||
public CsrfConfigurer(ApplicationContext context) {
|
||||
this.context = context;
|
||||
@ -156,16 +164,16 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
*
|
||||
* <pre>
|
||||
* http
|
||||
* .csrf()
|
||||
* .ignoringRequestMatchers((request) -> "XMLHttpRequest".equals(request.getHeader("X-Requested-With")))
|
||||
* .and()
|
||||
* .csrf((csrf) -> csrf
|
||||
* .ignoringRequestMatchers((request) -> "XMLHttpRequest".equals(request.getHeader("X-Requested-With"))))
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
public CsrfConfigurer<H> ignoringRequestMatchers(RequestMatcher... requestMatchers) {
|
||||
return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers).and();
|
||||
new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -184,9 +192,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
*
|
||||
* <pre>
|
||||
* http
|
||||
* .csrf()
|
||||
* .ignoringRequestMatchers("/sockjs/**")
|
||||
* .and()
|
||||
* .csrf((csrf) -> csrf
|
||||
* .ignoringRequestMatchers("/sockjs/**"))
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
@ -194,7 +201,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* @see AbstractRequestMatcherRegistry#requestMatchers(String...)
|
||||
*/
|
||||
public CsrfConfigurer<H> ignoringRequestMatchers(String... patterns) {
|
||||
return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(patterns).and();
|
||||
new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(patterns);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,6 +222,21 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Sensible CSRF defaults when used in combination with a single page application.
|
||||
* Creates a cookie-based token repository and a custom request handler to resolve the
|
||||
* actual token value instead of the encoded token.
|
||||
* </p>
|
||||
* @return the {@link CsrfConfigurer} for further customizations
|
||||
* @since 7.0
|
||||
*/
|
||||
public CsrfConfigurer<H> spa() {
|
||||
this.csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
|
||||
this.requestHandler = new SpaCsrfTokenRequestHandler();
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void configure(H http) {
|
||||
@ -363,10 +386,6 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
setApplicationContext(context);
|
||||
}
|
||||
|
||||
CsrfConfigurer<H> and() {
|
||||
return CsrfConfigurer.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IgnoreCsrfProtectionRegistry chainRequestMatchers(List<RequestMatcher> requestMatchers) {
|
||||
CsrfConfigurer.this.ignoredCsrfProtectionMatchers.addAll(requestMatchers);
|
||||
@ -375,4 +394,27 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
}
|
||||
|
||||
private static final class SpaCsrfTokenRequestHandler implements CsrfTokenRequestHandler {
|
||||
|
||||
private final CsrfTokenRequestAttributeHandler plain = new CsrfTokenRequestAttributeHandler();
|
||||
|
||||
private final CsrfTokenRequestAttributeHandler xor = new XorCsrfTokenRequestAttributeHandler();
|
||||
|
||||
SpaCsrfTokenRequestHandler() {
|
||||
this.xor.setCsrfRequestAttributeName(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken) {
|
||||
this.xor.handle(request, response, csrfToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
|
||||
String headerValue = request.getHeader(csrfToken.getHeaderName());
|
||||
return (StringUtils.hasText(headerValue) ? this.plain : this.xor).resolveCsrfTokenValue(request, csrfToken);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
@ -76,7 +77,7 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#exceptionHandling()
|
||||
* @see HttpSecurity#exceptionHandling(Customizer)
|
||||
*/
|
||||
public ExceptionHandlingConfigurer() {
|
||||
}
|
||||
|
@ -1,421 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.expression.WebExpressionVoter;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Adds URL based authorization based upon SpEL expressions to an application. At least
|
||||
* one {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped
|
||||
* to {@link ConfigAttribute}'s for this {@link SecurityContextConfigurer} to have
|
||||
* meaning.
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are populated to allow other
|
||||
* {@link org.springframework.security.config.annotation.SecurityConfigurer}'s to
|
||||
* customize:
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link AuthenticationTrustResolver} is optionally used to populate the
|
||||
* {@link DefaultWebSecurityExpressionHandler}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @author Rob Winch
|
||||
* @author Yanming Zhou
|
||||
* @author Ngoc Nhan
|
||||
* @since 3.2
|
||||
* @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()
|
||||
* @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> {
|
||||
|
||||
static final String permitAll = "permitAll";
|
||||
|
||||
private static final String denyAll = "denyAll";
|
||||
|
||||
private static final String anonymous = "anonymous";
|
||||
|
||||
private static final String authenticated = "authenticated";
|
||||
|
||||
private static final String fullyAuthenticated = "fullyAuthenticated";
|
||||
|
||||
private static final String rememberMe = "rememberMe";
|
||||
|
||||
private final String rolePrefix;
|
||||
|
||||
private final ExpressionInterceptUrlRegistry REGISTRY;
|
||||
|
||||
private SecurityExpressionHandler<FilterInvocation> expressionHandler;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#authorizeRequests()
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) {
|
||||
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBeanProvider(GrantedAuthorityDefaults.class)
|
||||
.getIfUnique();
|
||||
if (grantedAuthorityDefaults != null) {
|
||||
this.rolePrefix = grantedAuthorityDefaults.getRolePrefix();
|
||||
}
|
||||
else {
|
||||
this.rolePrefix = "ROLE_";
|
||||
}
|
||||
this.REGISTRY = new ExpressionInterceptUrlRegistry(context);
|
||||
}
|
||||
|
||||
public ExpressionInterceptUrlRegistry getRegistry() {
|
||||
return this.REGISTRY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows registering multiple {@link RequestMatcher} instances to a collection of
|
||||
* {@link ConfigAttribute} instances
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to register to the
|
||||
* {@link ConfigAttribute} instances
|
||||
* @param configAttributes the {@link ConfigAttribute} to be mapped by the
|
||||
* {@link RequestMatcher} instances
|
||||
*/
|
||||
private void interceptUrl(Iterable<? extends RequestMatcher> requestMatchers,
|
||||
Collection<ConfigAttribute> configAttributes) {
|
||||
for (RequestMatcher requestMatcher : requestMatchers) {
|
||||
this.REGISTRY.addMapping(
|
||||
new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
List<AccessDecisionVoter<?>> getDecisionVoters(H http) {
|
||||
List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
|
||||
WebExpressionVoter expressionVoter = new WebExpressionVoter();
|
||||
expressionVoter.setExpressionHandler(getExpressionHandler(http));
|
||||
decisionVoters.add(expressionVoter);
|
||||
return decisionVoters;
|
||||
}
|
||||
|
||||
@Override
|
||||
ExpressionBasedFilterInvocationSecurityMetadataSource createMetadataSource(H http) {
|
||||
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = this.REGISTRY.createRequestMap();
|
||||
Assert.state(!requestMap.isEmpty(),
|
||||
"At least one mapping is required (i.e. authorizeRequests().anyRequest().authenticated())");
|
||||
return new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, getExpressionHandler(http));
|
||||
}
|
||||
|
||||
private SecurityExpressionHandler<FilterInvocation> getExpressionHandler(H http) {
|
||||
if (this.expressionHandler != null) {
|
||||
return this.expressionHandler;
|
||||
}
|
||||
DefaultWebSecurityExpressionHandler defaultHandler = new DefaultWebSecurityExpressionHandler();
|
||||
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
|
||||
if (trustResolver != null) {
|
||||
defaultHandler.setTrustResolver(trustResolver);
|
||||
}
|
||||
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
|
||||
if (context != null) {
|
||||
context.getBeanProvider(RoleHierarchy.class).ifUnique(defaultHandler::setRoleHierarchy);
|
||||
context.getBeanProvider(GrantedAuthorityDefaults.class)
|
||||
.ifUnique((grantedAuthorityDefaults) -> defaultHandler
|
||||
.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix()));
|
||||
context.getBeanProvider(PermissionEvaluator.class).ifUnique(defaultHandler::setPermissionEvaluator);
|
||||
}
|
||||
this.expressionHandler = postProcess(defaultHandler);
|
||||
return this.expressionHandler;
|
||||
}
|
||||
|
||||
private static String hasAnyRole(String rolePrefix, String... authorities) {
|
||||
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','" + rolePrefix);
|
||||
return "hasAnyRole('" + rolePrefix + anyAuthorities + "')";
|
||||
}
|
||||
|
||||
private static String hasRole(String rolePrefix, String role) {
|
||||
Assert.notNull(role, "role cannot be null");
|
||||
Assert.isTrue(rolePrefix.isEmpty() || !role.startsWith(rolePrefix), () -> "role should not start with '"
|
||||
+ rolePrefix + "' since it is automatically inserted. Got '" + role + "'");
|
||||
return "hasRole('" + rolePrefix + role + "')";
|
||||
}
|
||||
|
||||
private static String hasAuthority(String authority) {
|
||||
return "hasAuthority('" + authority + "')";
|
||||
}
|
||||
|
||||
private static String hasAnyAuthority(String... authorities) {
|
||||
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','");
|
||||
return "hasAnyAuthority('" + anyAuthorities + "')";
|
||||
}
|
||||
|
||||
private static String hasIpAddress(String ipAddressExpression) {
|
||||
return "hasIpAddress('" + ipAddressExpression + "')";
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public final class ExpressionInterceptUrlRegistry extends
|
||||
ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<ExpressionInterceptUrlRegistry, AuthorizedUrl> {
|
||||
|
||||
private ExpressionInterceptUrlRegistry(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
|
||||
return new AuthorizedUrl(requestMatchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customization of the {@link SecurityExpressionHandler} to be used. The
|
||||
* default is {@link DefaultWebSecurityExpressionHandler}
|
||||
* @param expressionHandler the {@link SecurityExpressionHandler} to be used
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization.
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry expressionHandler(
|
||||
SecurityExpressionHandler<FilterInvocation> expressionHandler) {
|
||||
ExpressionUrlAuthorizationConfigurer.this.expressionHandler = expressionHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link ObjectPostProcessor} for this class.
|
||||
* @param objectPostProcessor
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customizations
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
public ExpressionInterceptUrlRegistry withObjectPostProcessor(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return this;
|
||||
}
|
||||
|
||||
public H and() {
|
||||
return ExpressionUrlAuthorizationConfigurer.this.and();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class AuthorizedUrl {
|
||||
|
||||
private List<? extends RequestMatcher> requestMatchers;
|
||||
|
||||
private boolean not;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to map
|
||||
*/
|
||||
AuthorizedUrl(List<? extends RequestMatcher> requestMatchers) {
|
||||
this.requestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
protected List<? extends RequestMatcher> getMatchers() {
|
||||
return this.requestMatchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negates the following expression.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public AuthorizedUrl not() {
|
||||
this.not = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for specifying URLs require a particular role. If you do not want to
|
||||
* have role prefix (default "ROLE_") automatically inserted see
|
||||
* {@link #hasAuthority(String)}.
|
||||
* @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not
|
||||
* start with role prefix as this is automatically inserted.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry hasRole(String role) {
|
||||
return access(ExpressionUrlAuthorizationConfigurer
|
||||
.hasRole(ExpressionUrlAuthorizationConfigurer.this.rolePrefix, role));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for specifying URLs require any of a number of roles. If you do not
|
||||
* want to have role prefix (default "ROLE_") automatically inserted see
|
||||
* {@link #hasAnyAuthority(String...)}
|
||||
* @param roles the roles to require (i.e. USER, ADMIN, etc). Note, it should not
|
||||
* start with role prefix as this is automatically inserted.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry hasAnyRole(String... roles) {
|
||||
return access(ExpressionUrlAuthorizationConfigurer
|
||||
.hasAnyRole(ExpressionUrlAuthorizationConfigurer.this.rolePrefix, roles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs require a particular authority.
|
||||
* @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry hasAuthority(String authority) {
|
||||
return access(ExpressionUrlAuthorizationConfigurer.hasAuthority(authority));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs requires any of a number authorities.
|
||||
* @param authorities the requests require at least one of the authorities (i.e.
|
||||
* "ROLE_USER","ROLE_ADMIN" would mean either "ROLE_USER" or "ROLE_ADMIN" is
|
||||
* required).
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry hasAnyAuthority(String... authorities) {
|
||||
return access(ExpressionUrlAuthorizationConfigurer.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs requires a specific IP Address or subnet.
|
||||
* @param ipaddressExpression the ipaddress (i.e. 192.168.1.79) or local subnet
|
||||
* (i.e. 192.168.0/24)
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry hasIpAddress(String ipaddressExpression) {
|
||||
return access(ExpressionUrlAuthorizationConfigurer.hasIpAddress(ipaddressExpression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by anyone.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry permitAll() {
|
||||
return access(permitAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by anonymous users.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry anonymous() {
|
||||
return access(anonymous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by users that have been remembered.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
* @see RememberMeConfigurer
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry rememberMe() {
|
||||
return access(rememberMe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are not allowed by anyone.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry denyAll() {
|
||||
return access(denyAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by any authenticated user.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry authenticated() {
|
||||
return access(authenticated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by users who have authenticated and were not
|
||||
* "remembered".
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
* @see RememberMeConfigurer
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry fullyAuthenticated() {
|
||||
return access(fullyAuthenticated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying that URLs are secured by an arbitrary expression
|
||||
* @param attribute the expression to secure the URLs (i.e. "hasRole('ROLE_USER')
|
||||
* and hasRole('ROLE_SUPER')")
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry access(String attribute) {
|
||||
if (this.not) {
|
||||
attribute = "!" + attribute;
|
||||
}
|
||||
interceptUrl(this.requestMatchers, SecurityConfig.createList(attribute));
|
||||
return ExpressionUrlAuthorizationConfigurer.this.REGISTRY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -17,8 +17,8 @@
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
@ -74,7 +74,7 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#formLogin()
|
||||
* @see HttpSecurity#formLogin(Customizer)
|
||||
*/
|
||||
public FormLoginConfigurer() {
|
||||
super(new UsernamePasswordAuthenticationFilter(), null);
|
||||
@ -235,7 +235,7 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
|
||||
@Override
|
||||
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
|
||||
return RequestMatcherFactory.matcher(HttpMethod.POST, loginProcessingUrl);
|
||||
return getRequestMatcherBuilder().matcher(HttpMethod.POST, loginProcessingUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,7 +111,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @see HttpSecurity#headers()
|
||||
* @see HttpSecurity#headers(Customizer)
|
||||
*/
|
||||
public HeadersConfigurer() {
|
||||
}
|
||||
@ -127,26 +127,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the
|
||||
* <a href= "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
|
||||
* >X-Content-Type-Options</a>:
|
||||
*
|
||||
* <pre>
|
||||
* X-Content-Type-Options: nosniff
|
||||
* </pre>
|
||||
* @return the {@link ContentTypeOptionsConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)} or
|
||||
* {@code contentTypeOptions(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ContentTypeOptionsConfig contentTypeOptions() {
|
||||
return this.contentTypeOptions.enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the
|
||||
* <a href= "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
|
||||
@ -164,26 +144,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <strong>Note this is not comprehensive XSS protection!</strong>
|
||||
*
|
||||
* <p>
|
||||
* Allows customizing the {@link XXssProtectionHeaderWriter} which adds the <a href=
|
||||
* "https://web.archive.org/web/20160201174302/https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
|
||||
* >X-XSS-Protection header</a>
|
||||
* </p>
|
||||
* @return the {@link XXssConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or
|
||||
* {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public XXssConfig xssProtection() {
|
||||
return this.xssProtection.enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* <strong>Note this is not comprehensive XSS protection!</strong>
|
||||
*
|
||||
@ -201,26 +161,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the
|
||||
* following headers:
|
||||
* <ul>
|
||||
* <li>Cache-Control: no-cache, no-store, max-age=0, must-revalidate</li>
|
||||
* <li>Pragma: no-cache</li>
|
||||
* <li>Expires: 0</li>
|
||||
* </ul>
|
||||
* @return the {@link CacheControlConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #cacheControl(Customizer)} or
|
||||
* {@code cacheControl(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CacheControlConfig cacheControl() {
|
||||
return this.cacheControl.enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the
|
||||
* following headers:
|
||||
@ -238,19 +178,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link HstsHeaderWriter} which provides support for
|
||||
* <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
|
||||
* (HSTS)</a>.
|
||||
* @return the {@link HstsConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #httpStrictTransportSecurity(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HstsConfig httpStrictTransportSecurity() {
|
||||
return this.hsts.enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link HstsHeaderWriter} which provides support for
|
||||
* <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
|
||||
@ -264,20 +191,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link XFrameOptionsHeaderWriter}.
|
||||
* @return the {@link FrameOptionsConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or
|
||||
* {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public FrameOptionsConfig frameOptions() {
|
||||
return this.frameOptions.enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link XFrameOptionsHeaderWriter}.
|
||||
* @param frameOptionsCustomizer the {@link Customizer} to provide more options for
|
||||
@ -289,21 +202,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link HpkpHeaderWriter} which provides support for
|
||||
* <a href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
|
||||
* @return the {@link HpkpConfig} for additional customizations
|
||||
*
|
||||
* @since 4.1
|
||||
* @deprecated see <a href=
|
||||
* "https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning">Certificate
|
||||
* and Public Key Pinning</a> for more context
|
||||
*/
|
||||
@Deprecated
|
||||
public HpkpConfig httpPublicKeyPinning() {
|
||||
return this.hpkp.enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link HpkpHeaderWriter} which provides support for
|
||||
* <a href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
|
||||
@ -320,39 +218,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security
|
||||
* Policy (CSP) Level 2</a>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the Content-Security-Policy
|
||||
* header in the response using the supplied security policy directive(s).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which
|
||||
* supports the writing of the two headers as detailed in the W3C Candidate
|
||||
* Recommendation:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Content-Security-Policy</li>
|
||||
* <li>Content-Security-Policy-Report-Only</li>
|
||||
* </ul>
|
||||
* @return the {@link ContentSecurityPolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if policyDirectives is null or empty
|
||||
* @since 4.1
|
||||
* @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)}
|
||||
* instead
|
||||
* @see ContentSecurityPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ContentSecurityPolicyConfig contentSecurityPolicy(String policyDirectives) {
|
||||
this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(policyDirectives);
|
||||
return this.contentSecurityPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security
|
||||
@ -454,71 +319,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
|
||||
* Policy</a>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support
|
||||
* the writing of the header as detailed in the W3C Technical Report:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Referrer-Policy</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Default value is:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* Referrer-Policy: no-referrer
|
||||
* </pre>
|
||||
* @return the {@link ReferrerPolicyConfig} for additional configuration
|
||||
* @since 4.2
|
||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or
|
||||
* {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see ReferrerPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ReferrerPolicyConfig referrerPolicy() {
|
||||
this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter();
|
||||
return this.referrerPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
|
||||
* Policy</a>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support
|
||||
* the writing of the header as detailed in the W3C Technical Report:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Referrer-Policy</li>
|
||||
* </ul>
|
||||
* @return the {@link ReferrerPolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if policy is null or empty
|
||||
* @since 4.2
|
||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or
|
||||
* {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see ReferrerPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) {
|
||||
this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(policy);
|
||||
return this.referrerPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
|
||||
@ -568,35 +368,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this.featurePolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Allows configuration for
|
||||
* <a href="https://w3c.github.io/webappsec-permissions-policy/">Permissions
|
||||
* Policy</a>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Configuration is provided to the {@link PermissionsPolicyHeaderWriter} which
|
||||
* support the writing of the header as detailed in the W3C Technical Report:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Permissions-Policy</li>
|
||||
* </ul>
|
||||
* @return the {@link PermissionsPolicyConfig} for additional configuration
|
||||
* @since 5.5
|
||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicyHeader(Customizer)} or
|
||||
* {@code permissionsPolicy(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see PermissionsPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public PermissionsPolicyConfig permissionsPolicy() {
|
||||
this.permissionsPolicy.writer = new PermissionsPolicyHeaderWriter();
|
||||
return this.permissionsPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for
|
||||
* <a href="https://w3c.github.io/webappsec-permissions-policy/"> Permissions
|
||||
@ -643,26 +414,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which
|
||||
* responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link CrossOriginOpenerPolicyConfig} for additional confniguration
|
||||
* @since 5.7
|
||||
* @deprecated For removal in 7.0. Use {@link #crossOriginOpenerPolicy(Customizer)}
|
||||
* instead
|
||||
* @see CrossOriginOpenerPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy() {
|
||||
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
|
||||
return this.crossOriginOpenerPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
@ -687,26 +438,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter}
|
||||
* which is responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional customizations
|
||||
* @since 5.7
|
||||
* @deprecated For removal in 7.0. Use {@link #crossOriginEmbedderPolicy(Customizer)}
|
||||
* instead
|
||||
* @see CrossOriginEmbedderPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy() {
|
||||
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
|
||||
return this.crossOriginEmbedderPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
@ -731,26 +462,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginResourcePolicyHeaderWriter}
|
||||
* which is responsible for writing the header:
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @deprecated For removal in 7.0. Use {@link #crossOriginResourcePolicy(Customizer)}
|
||||
* instead
|
||||
* @see CrossOriginResourcePolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CrossOriginResourcePolicyConfig crossOriginResourcePolicy() {
|
||||
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
|
||||
return this.crossOriginResourcePolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
@ -789,17 +500,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
*/
|
||||
public HeadersConfigurer<H> disable() {
|
||||
this.writer = null;
|
||||
return and();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link HeadersConfigurer}
|
||||
* @return the {@link HeadersConfigurer} for additional customization
|
||||
* @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
@ -864,21 +564,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
*/
|
||||
public HeadersConfigurer<H> disable() {
|
||||
this.writer = null;
|
||||
return and();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of X-XSS-Protection and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or
|
||||
* {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
@ -912,21 +597,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cache Control and continuing configuration
|
||||
* of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #cacheControl(Customizer)} or
|
||||
* {@code cacheControl(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the Cache Control headers are enabled if they are not already.
|
||||
* @return the {@link CacheControlConfig} for additional customization
|
||||
@ -1024,18 +694,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Strict Transport Security and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #httpStrictTransportSecurity(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that Strict-Transport-Security is enabled if it is not already
|
||||
* @return the {@link HstsConfig} for additional customization
|
||||
@ -1063,7 +721,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
*/
|
||||
public HeadersConfigurer<H> deny() {
|
||||
this.writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY);
|
||||
return and();
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1077,7 +735,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
*/
|
||||
public HeadersConfigurer<H> sameOrigin() {
|
||||
this.writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN);
|
||||
return and();
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1086,20 +744,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
*/
|
||||
public HeadersConfigurer<H> disable() {
|
||||
this.writer = null;
|
||||
return and();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows continuing customizing the headers configuration.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or
|
||||
* {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
@ -1317,18 +961,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Content Security Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class ReferrerPolicyConfig {
|
||||
@ -1349,18 +981,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or
|
||||
* {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class FeaturePolicyConfig {
|
||||
@ -1399,18 +1019,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Permissions Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class CrossOriginOpenerPolicyConfig {
|
||||
@ -1432,18 +1040,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cross Origin Opener Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginOpenerPolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class CrossOriginEmbedderPolicyConfig {
|
||||
@ -1466,18 +1062,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cross-Origin-Embedder-Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginEmbedderPolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class CrossOriginResourcePolicyConfig {
|
||||
@ -1500,18 +1084,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cross-Origin-Resource-Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginResourcePolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
@ -98,7 +99,7 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#httpBasic()
|
||||
* @see HttpSecurity#httpBasic(Customizer)
|
||||
*/
|
||||
public HttpBasicConfigurer() {
|
||||
realmName(DEFAULT_REALM);
|
||||
|
@ -22,6 +22,7 @@ import java.util.Set;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever;
|
||||
@ -77,7 +78,7 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends Abstr
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#jee()
|
||||
* @see HttpSecurity#jee(Customizer)
|
||||
*/
|
||||
public JeeConfigurer() {
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ import java.util.List;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
|
||||
@ -92,7 +92,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#logout()
|
||||
* @see HttpSecurity#logout(Customizer)
|
||||
*/
|
||||
public LogoutConfigurer() {
|
||||
}
|
||||
@ -145,12 +145,12 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* (i.e. log out) to protect against
|
||||
* <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF
|
||||
* attacks</a>. If you really want to use an HTTP GET, you can use
|
||||
* <code>logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GEt, logoutUrl));</code>
|
||||
* <code>logoutRequestMatcher(PathPatternRequestMatcher.pathPattern(HttpMethod.GEt, logoutUrl));</code>
|
||||
* </p>
|
||||
* @param logoutUrl the URL that will invoke logout.
|
||||
* @return the {@link LogoutConfigurer} for further customization
|
||||
* @see #logoutRequestMatcher(RequestMatcher)
|
||||
* @see HttpSecurity#csrf()
|
||||
* @see HttpSecurity#csrf(Customizer)
|
||||
*/
|
||||
public LogoutConfigurer<H> logoutUrl(String logoutUrl) {
|
||||
this.logoutRequestMatcher = null;
|
||||
@ -369,7 +369,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
|
||||
private RequestMatcher createLogoutRequestMatcher(String httpMethod) {
|
||||
return RequestMatcherFactory.matcher(HttpMethod.valueOf(httpMethod), this.logoutUrl);
|
||||
return getRequestMatcherBuilder().matcher(HttpMethod.valueOf(httpMethod), this.logoutUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.web.RequestMatcherRedirectFilter;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.util.Assert;
|
||||
@ -55,7 +54,7 @@ public final class PasswordManagementConfigurer<B extends HttpSecurityBuilder<B>
|
||||
@Override
|
||||
public void configure(B http) throws Exception {
|
||||
RequestMatcherRedirectFilter changePasswordFilter = new RequestMatcherRedirectFilter(
|
||||
RequestMatcherFactory.matcher(WELL_KNOWN_CHANGE_PASSWORD_PATTERN), this.changePasswordPage);
|
||||
getRequestMatcherBuilder().matcher(WELL_KNOWN_CHANGE_PASSWORD_PATTERN), this.changePasswordPage);
|
||||
http.addFilterBefore(postProcess(changePasswordFilter), UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
|
@ -18,10 +18,8 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.authorization.SingleResultAuthorizationManager;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry.UrlMapping;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@ -47,25 +45,14 @@ final class PermitAllSupport {
|
||||
@SuppressWarnings("unchecked")
|
||||
static void permitAll(HttpSecurityBuilder<? extends HttpSecurityBuilder<?>> http,
|
||||
RequestMatcher... requestMatchers) {
|
||||
ExpressionUrlAuthorizationConfigurer<?> configurer = http
|
||||
.getConfigurer(ExpressionUrlAuthorizationConfigurer.class);
|
||||
AuthorizeHttpRequestsConfigurer<?> httpConfigurer = http.getConfigurer(AuthorizeHttpRequestsConfigurer.class);
|
||||
|
||||
boolean oneConfigurerPresent = configurer == null ^ httpConfigurer == null;
|
||||
Assert.state(oneConfigurerPresent,
|
||||
"permitAll only works with either HttpSecurity.authorizeRequests() or HttpSecurity.authorizeHttpRequests(). "
|
||||
+ "Please define one or the other but not both.");
|
||||
Assert.state(httpConfigurer != null,
|
||||
"permitAll only works with HttpSecurity.authorizeHttpRequests(). Please define one.");
|
||||
|
||||
for (RequestMatcher matcher : requestMatchers) {
|
||||
if (matcher != null) {
|
||||
if (configurer != null) {
|
||||
configurer.getRegistry()
|
||||
.addMapping(0, new UrlMapping(matcher,
|
||||
SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
|
||||
}
|
||||
else {
|
||||
httpConfigurer.addFirst(matcher, SingleResultAuthorizationManager.permitAll());
|
||||
}
|
||||
httpConfigurer.addFirst(matcher, SingleResultAuthorizationManager.permitAll());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,14 +24,12 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
||||
@ -145,10 +143,13 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
RequestMatcher notFavIcon = new NegatedRequestMatcher(getFaviconRequestMatcher());
|
||||
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
|
||||
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
|
||||
RequestMatcher notWebSocket = new NegatedRequestMatcher(
|
||||
new RequestHeaderRequestMatcher("Upgrade", "websocket"));
|
||||
|
||||
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
if (isCsrfEnabled) {
|
||||
RequestMatcher getRequests = RequestMatcherFactory.matcher(HttpMethod.GET, "/**");
|
||||
RequestMatcher getRequests = getRequestMatcherBuilder().matcher(HttpMethod.GET, "/**");
|
||||
matchers.add(0, getRequests);
|
||||
}
|
||||
matchers.add(notFavIcon);
|
||||
@ -156,6 +157,7 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
matchers.add(notXRequestedWith);
|
||||
matchers.add(notMatchingMediaType(http, MediaType.MULTIPART_FORM_DATA));
|
||||
matchers.add(notMatchingMediaType(http, MediaType.TEXT_EVENT_STREAM));
|
||||
matchers.add(notWebSocket);
|
||||
return new AndRequestMatcher(matchers);
|
||||
}
|
||||
|
||||
@ -170,12 +172,7 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
|
||||
private RequestMatcher getFaviconRequestMatcher() {
|
||||
if (RequestMatcherFactory.usesPathPatterns()) {
|
||||
return RequestMatcherFactory.matcher("/favicon.*");
|
||||
}
|
||||
else {
|
||||
return new AntPathRequestMatcher("/**/favicon.*");
|
||||
}
|
||||
return getRequestMatcherBuilder().matcher("/favicon.*");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
@ -70,7 +71,7 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#securityContext()
|
||||
* @see HttpSecurity#securityContext(Customizer)
|
||||
*/
|
||||
public SecurityContextConfigurer() {
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
@ -66,7 +67,7 @@ public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#servletApi()
|
||||
* @see HttpSecurity#servletApi(Customizer)
|
||||
*/
|
||||
public ServletApiConfigurer() {
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#sessionManagement()
|
||||
* @see HttpSecurity#sessionManagement(Customizer)
|
||||
*/
|
||||
public SessionManagementConfigurer() {
|
||||
}
|
||||
@ -775,17 +775,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to chain back to the {@link SessionManagementConfigurer}
|
||||
* @return the {@link SessionManagementConfigurer} for further customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #sessionConcurrency(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public SessionManagementConfigurer<H> and() {
|
||||
return SessionManagementConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,341 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Adds URL based authorization using
|
||||
* {@link DefaultFilterInvocationSecurityMetadataSource}. At least one
|
||||
* {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped to
|
||||
* {@link ConfigAttribute}'s for this {@link SecurityContextConfigurer} to have meaning.
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* <p>
|
||||
* Usage includes applying the {@link UrlAuthorizationConfigurer} and then modifying the
|
||||
* StandardInterceptUrlRegistry. For example:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* @Bean
|
||||
* public SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context) throws Exception {
|
||||
* http.apply(new UrlAuthorizationConfigurer<HttpSecurity>(context)).getRegistry()
|
||||
* .requestMatchers("/users**", "/sessions/**").hasRole("USER")
|
||||
* .requestMatchers("/signup").hasRole("ANONYMOUS").anyRequest().hasRole("USER");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* The following Filters are populated
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* The following shared objects are populated to allow other
|
||||
* {@link org.springframework.security.config.annotation.SecurityConfigurer}'s to
|
||||
* customize:
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>AuthenticationManager</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see ExpressionUrlAuthorizationConfigurer
|
||||
* @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractInterceptUrlConfigurer<UrlAuthorizationConfigurer<H>, H> {
|
||||
|
||||
private final StandardInterceptUrlRegistry registry;
|
||||
|
||||
public UrlAuthorizationConfigurer(ApplicationContext context) {
|
||||
this.registry = new StandardInterceptUrlRegistry(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* The StandardInterceptUrlRegistry is what users will interact with after applying
|
||||
* the {@link UrlAuthorizationConfigurer}.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations
|
||||
*/
|
||||
public StandardInterceptUrlRegistry getRegistry() {
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link ObjectPostProcessor} for this class.
|
||||
* @param objectPostProcessor
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customizations
|
||||
*/
|
||||
@Override
|
||||
public UrlAuthorizationConfigurer<H> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated(since = "6.4", forRemoval = true)
|
||||
@Override
|
||||
public UrlAuthorizationConfigurer<H> withObjectPostProcessor(
|
||||
org.springframework.security.config.annotation.ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the default {@link AccessDecisionVoter} instances used if an
|
||||
* {@link AccessDecisionManager} was not specified.
|
||||
* @param http the builder to use
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
List<AccessDecisionVoter<?>> getDecisionVoters(H http) {
|
||||
List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
|
||||
decisionVoters.add(new RoleVoter());
|
||||
decisionVoters.add(new AuthenticatedVoter());
|
||||
return decisionVoters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link FilterInvocationSecurityMetadataSource} to use. The
|
||||
* implementation is a {@link DefaultFilterInvocationSecurityMetadataSource}.
|
||||
* @param http the builder to use
|
||||
*/
|
||||
@Override
|
||||
FilterInvocationSecurityMetadataSource createMetadataSource(H http) {
|
||||
return new DefaultFilterInvocationSecurityMetadataSource(this.registry.createRequestMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mapping of the {@link RequestMatcher} instances to the
|
||||
* {@link ConfigAttribute} instances.
|
||||
* @param requestMatchers the {@link RequestMatcher} instances that should map to the
|
||||
* provided {@link ConfigAttribute} instances
|
||||
* @param configAttributes the {@link ConfigAttribute} instances that should be mapped
|
||||
* by the {@link RequestMatcher} instances
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations
|
||||
*/
|
||||
private StandardInterceptUrlRegistry addMapping(Iterable<? extends RequestMatcher> requestMatchers,
|
||||
Collection<ConfigAttribute> configAttributes) {
|
||||
for (RequestMatcher requestMatcher : requestMatchers) {
|
||||
this.registry.addMapping(
|
||||
new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
|
||||
}
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a String for specifying a user requires a role.
|
||||
* @param role the role that should be required which is prepended with ROLE_
|
||||
* automatically (i.e. USER, ADMIN, etc). It should not start with ROLE_
|
||||
* @return the {@link ConfigAttribute} expressed as a String
|
||||
*/
|
||||
private static String hasRole(String role) {
|
||||
Assert.isTrue(!role.startsWith("ROLE_"), () -> role
|
||||
+ " should not start with ROLE_ since ROLE_ is automatically prepended when using hasRole. Consider using hasAuthority or access instead.");
|
||||
return "ROLE_" + role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a String for specifying that a user requires one of many roles.
|
||||
* @param roles the roles that the user should have at least one of (i.e. ADMIN, USER,
|
||||
* etc). Each role should not start with ROLE_ since it is automatically prepended
|
||||
* already.
|
||||
* @return the {@link ConfigAttribute} expressed as a String
|
||||
*/
|
||||
private static String[] hasAnyRole(String... roles) {
|
||||
for (int i = 0; i < roles.length; i++) {
|
||||
roles[i] = "ROLE_" + roles[i];
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a String for specifying that a user requires one of many authorities
|
||||
* @param authorities the authorities that the user should have at least one of (i.e.
|
||||
* ROLE_USER, ROLE_ADMIN, etc).
|
||||
* @return the {@link ConfigAttribute} expressed as a String.
|
||||
*/
|
||||
private static String[] hasAnyAuthority(String... authorities) {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public final class StandardInterceptUrlRegistry extends
|
||||
UrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<StandardInterceptUrlRegistry, AuthorizedUrl> {
|
||||
|
||||
private StandardInterceptUrlRegistry(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizedUrl requestMatchers(String... patterns) {
|
||||
return super.requestMatchers(patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizedUrl requestMatchers(HttpMethod method, String... patterns) {
|
||||
return super.requestMatchers(method, patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizedUrl requestMatchers(HttpMethod method) {
|
||||
return super.requestMatchers(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizedUrl requestMatchers(RequestMatcher... requestMatchers) {
|
||||
return super.requestMatchers(requestMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
|
||||
return new AuthorizedUrl(requestMatchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link ObjectPostProcessor} for this class.
|
||||
* @param objectPostProcessor
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customizations
|
||||
*/
|
||||
public StandardInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
|
||||
addObjectPostProcessor(objectPostProcessor);
|
||||
return this;
|
||||
}
|
||||
|
||||
public H and() {
|
||||
return UrlAuthorizationConfigurer.this.and();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the specified {@link RequestMatcher} instances to {@link ConfigAttribute}
|
||||
* instances.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public class AuthorizedUrl {
|
||||
|
||||
private final List<? extends RequestMatcher> requestMatchers;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to map to some
|
||||
* {@link ConfigAttribute} instances.
|
||||
*/
|
||||
AuthorizedUrl(List<? extends RequestMatcher> requestMatchers) {
|
||||
Assert.notEmpty(requestMatchers, "requestMatchers must contain at least one value");
|
||||
this.requestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a user requires a role.
|
||||
* @param role the role that should be required which is prepended with ROLE_
|
||||
* automatically (i.e. USER, ADMIN, etc). It should not start with ROLE_ the
|
||||
* {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public StandardInterceptUrlRegistry hasRole(String role) {
|
||||
return access(UrlAuthorizationConfigurer.hasRole(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that a user requires one of many roles.
|
||||
* @param roles the roles that the user should have at least one of (i.e. ADMIN,
|
||||
* USER, etc). Each role should not start with ROLE_ since it is automatically
|
||||
* prepended already.
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public StandardInterceptUrlRegistry hasAnyRole(String... roles) {
|
||||
return access(UrlAuthorizationConfigurer.hasAnyRole(roles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a user requires an authority.
|
||||
* @param authority the authority that should be required
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public StandardInterceptUrlRegistry hasAuthority(String authority) {
|
||||
return access(authority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that a user requires one of many authorities
|
||||
* @param authorities the authorities that the user should have at least one of
|
||||
* (i.e. ROLE_USER, ROLE_ADMIN, etc).
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public StandardInterceptUrlRegistry hasAnyAuthority(String... authorities) {
|
||||
return access(UrlAuthorizationConfigurer.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that an anonymous user is allowed access
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public StandardInterceptUrlRegistry anonymous() {
|
||||
return hasRole("ANONYMOUS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that the user must have the specified {@link ConfigAttribute}'s
|
||||
* @param attributes the {@link ConfigAttribute}'s that restrict access to a URL
|
||||
* @return the {@link UrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public StandardInterceptUrlRegistry access(String... attributes) {
|
||||
addMapping(this.requestMatchers, SecurityConfig.createList(attributes));
|
||||
return UrlAuthorizationConfigurer.this.registry;
|
||||
}
|
||||
|
||||
protected List<? extends RequestMatcher> getMatchers() {
|
||||
return this.requestMatchers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -21,6 +21,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@ -90,7 +91,7 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @see HttpSecurity#x509()
|
||||
* @see HttpSecurity#x509(Customizer)
|
||||
*/
|
||||
public X509Configurer() {
|
||||
}
|
||||
@ -161,7 +162,10 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
|
||||
* @param subjectPrincipalRegex the regex to extract the user principal from the
|
||||
* certificate (i.e. "CN=(.*?)(?:,|$)").
|
||||
* @return the {@link X509Configurer} for further customizations
|
||||
* @deprecated Please use {{@link #x509PrincipalExtractor(X509PrincipalExtractor)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public X509Configurer<H> subjectPrincipalRegex(String subjectPrincipalRegex) {
|
||||
SubjectDnX509PrincipalExtractor principalExtractor = new SubjectDnX509PrincipalExtractor();
|
||||
principalExtractor.setSubjectDnRegex(subjectPrincipalRegex);
|
||||
|
@ -24,9 +24,9 @@ import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.RestClientAuthorizationCodeTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
|
||||
@ -141,18 +141,6 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AuthorizationCodeGrantConfigurer} for configuring the OAuth 2.0
|
||||
* Authorization Code Grant.
|
||||
* @return the {@link AuthorizationCodeGrantConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizationCodeGrant(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AuthorizationCodeGrantConfigurer authorizationCodeGrant() {
|
||||
return this.authorizationCodeGrantConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the OAuth 2.0 Authorization Code Grant.
|
||||
* @param authorizationCodeGrantCustomizer the {@link Customizer} to provide more
|
||||
@ -242,17 +230,6 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link OAuth2ClientConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2ClientConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizationCodeGrant(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ClientConfigurer<B> and() {
|
||||
return OAuth2ClientConfigurer.this;
|
||||
}
|
||||
|
||||
private void init(B builder) {
|
||||
OAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider = new OAuth2AuthorizationCodeAuthenticationProvider(
|
||||
getAccessTokenResponseClient());
|
||||
@ -320,7 +297,7 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(OAuth2AccessTokenResponseClient.class,
|
||||
OAuth2AuthorizationCodeGrantRequest.class);
|
||||
OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> bean = getBeanOrNull(resolvableType);
|
||||
return (bean != null) ? bean : new DefaultAuthorizationCodeTokenResponseClient();
|
||||
return (bean != null) ? bean : new RestClientAuthorizationCodeTokenResponseClient();
|
||||
}
|
||||
|
||||
private ClientRegistrationRepository getClientRegistrationRepository(B builder) {
|
||||
|
@ -38,7 +38,6 @@ import org.springframework.core.ResolvableType;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
@ -53,9 +52,9 @@ import org.springframework.security.core.session.SessionIdChangedEvent;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
|
||||
import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.RestClientAuthorizationCodeTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizedClientRefreshedEventListener;
|
||||
import org.springframework.security.oauth2.client.oidc.session.InMemoryOidcSessionRegistry;
|
||||
@ -155,7 +154,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @author Kazuki Shimizu
|
||||
* @author Ngoc Nhan
|
||||
* @since 5.0
|
||||
* @see HttpSecurity#oauth2Login()
|
||||
* @see HttpSecurity#oauth2Login(Customizer)
|
||||
* @see OAuth2AuthorizationRequestRedirectFilter
|
||||
* @see OAuth2LoginAuthenticationFilter
|
||||
* @see ClientRegistrationRepository
|
||||
@ -259,18 +258,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AuthorizationEndpointConfig} for configuring the Authorization
|
||||
* Server's Authorization Endpoint.
|
||||
* @return the {@link AuthorizationEndpointConfig}
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizationEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AuthorizationEndpointConfig authorizationEndpoint() {
|
||||
return this.authorizationEndpointConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Authorization Server's Authorization Endpoint.
|
||||
* @param authorizationEndpointCustomizer the {@link Customizer} to provide more
|
||||
@ -283,21 +270,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TokenEndpointConfig} for configuring the Authorization Server's
|
||||
* Token Endpoint.
|
||||
* @return the {@link TokenEndpointConfig}
|
||||
* @deprecated For removal in 7.0. Use {@link #tokenEndpoint(Customizer)} or
|
||||
* {@code tokenEndpoint(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public TokenEndpointConfig tokenEndpoint() {
|
||||
return this.tokenEndpointConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Authorization Server's Token Endpoint.
|
||||
* @param tokenEndpointCustomizer the {@link Customizer} to provide more options for
|
||||
@ -310,18 +282,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link RedirectionEndpointConfig} for configuring the Client's
|
||||
* Redirection Endpoint.
|
||||
* @return the {@link RedirectionEndpointConfig}
|
||||
* @deprecated For removal in 7.0. Use {@link #redirectionEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public RedirectionEndpointConfig redirectionEndpoint() {
|
||||
return this.redirectionEndpointConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Client's Redirection Endpoint.
|
||||
* @param redirectionEndpointCustomizer the {@link Customizer} to provide more options
|
||||
@ -334,21 +294,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link UserInfoEndpointConfig} for configuring the Authorization
|
||||
* Server's UserInfo Endpoint.
|
||||
* @return the {@link UserInfoEndpointConfig}
|
||||
* @deprecated For removal in 7.0. Use {@link #userInfoEndpoint(Customizer)} or
|
||||
* {@code userInfoEndpoint(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public UserInfoEndpointConfig userInfoEndpoint() {
|
||||
return this.userInfoEndpointConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Authorization Server's UserInfo Endpoint.
|
||||
* @param userInfoEndpointCustomizer the {@link Customizer} to provide more options
|
||||
@ -364,7 +309,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
public void init(B http) throws Exception {
|
||||
OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter(
|
||||
this.getClientRegistrationRepository(), this.getAuthorizedClientRepository(), this.loginProcessingUrl);
|
||||
RequestMatcher processUri = RequestMatcherFactory.matcher(this.loginProcessingUrl);
|
||||
RequestMatcher processUri = getRequestMatcherBuilder().matcher(this.loginProcessingUrl);
|
||||
authenticationFilter.setRequiresAuthenticationRequestMatcher(processUri);
|
||||
authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
if (this.securityContextRepository != null) {
|
||||
@ -451,7 +396,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
OAuth2LoginAuthenticationFilter authenticationFilter = this.getAuthenticationFilter();
|
||||
if (this.redirectionEndpointConfig.authorizationResponseBaseUri != null) {
|
||||
authenticationFilter.setRequiresAuthenticationRequestMatcher(
|
||||
RequestMatcherFactory.matcher(this.redirectionEndpointConfig.authorizationResponseBaseUri));
|
||||
getRequestMatcherBuilder().matcher(this.redirectionEndpointConfig.authorizationResponseBaseUri));
|
||||
}
|
||||
if (this.authorizationEndpointConfig.authorizationRequestRepository != null) {
|
||||
authenticationFilter
|
||||
@ -463,7 +408,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
@Override
|
||||
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
|
||||
return RequestMatcherFactory.matcher(loginProcessingUrl);
|
||||
return getRequestMatcherBuilder().matcher(loginProcessingUrl);
|
||||
}
|
||||
|
||||
private OAuth2AuthorizationRequestResolver getAuthorizationRequestResolver() {
|
||||
@ -532,7 +477,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(OAuth2AccessTokenResponseClient.class,
|
||||
OAuth2AuthorizationCodeGrantRequest.class);
|
||||
OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> bean = getBeanOrNull(resolvableType);
|
||||
return (bean != null) ? bean : new DefaultAuthorizationCodeTokenResponseClient();
|
||||
return (bean != null) ? bean : new RestClientAuthorizationCodeTokenResponseClient();
|
||||
}
|
||||
|
||||
private OAuth2UserService<OidcUserRequest, OidcUser> getOidcUserService() {
|
||||
@ -601,8 +546,8 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
}
|
||||
|
||||
private AuthenticationEntryPoint getLoginEntryPoint(B http, String providerLoginPage) {
|
||||
RequestMatcher loginPageMatcher = RequestMatcherFactory.matcher(this.getLoginPage());
|
||||
RequestMatcher faviconMatcher = RequestMatcherFactory.matcher("/favicon.ico");
|
||||
RequestMatcher loginPageMatcher = getRequestMatcherBuilder().matcher(this.getLoginPage());
|
||||
RequestMatcher faviconMatcher = getRequestMatcherBuilder().matcher("/favicon.ico");
|
||||
RequestMatcher defaultEntryPointMatcher = this.getAuthenticationEntryPointMatcher(http);
|
||||
RequestMatcher defaultLoginPageMatcher = new AndRequestMatcher(
|
||||
new OrRequestMatcher(loginPageMatcher, faviconMatcher), defaultEntryPointMatcher);
|
||||
@ -738,17 +683,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2LoginConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizationEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginConfigurer<B> and() {
|
||||
return OAuth2LoginConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -775,20 +709,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2LoginConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #tokenEndpoint(Customizer)} or
|
||||
* {@code tokenEndpoint(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginConfigurer<B> and() {
|
||||
return OAuth2LoginConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -813,17 +733,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2LoginConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #redirectionEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginConfigurer<B> and() {
|
||||
return OAuth2LoginConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -878,17 +787,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2LoginConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #userInfoEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginConfigurer<B> and() {
|
||||
return OAuth2LoginConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class OidcAuthenticationRequestChecker implements AuthenticationProvider {
|
||||
|
@ -18,11 +18,6 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.cl
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.nimbusds.jose.JOSEObjectType;
|
||||
import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
|
||||
import com.nimbusds.jose.proc.JOSEObjectTypeVerifier;
|
||||
import com.nimbusds.jose.proc.SecurityContext;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@ -38,6 +33,7 @@ import org.springframework.security.oauth2.jwt.BadJwtException;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
|
||||
import org.springframework.security.oauth2.jwt.JwtTypeValidator;
|
||||
import org.springframework.security.oauth2.jwt.JwtValidators;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.util.Assert;
|
||||
@ -67,8 +63,10 @@ final class OidcBackChannelLogoutAuthenticationProvider implements Authenticatio
|
||||
* Construct an {@link OidcBackChannelLogoutAuthenticationProvider}
|
||||
*/
|
||||
OidcBackChannelLogoutAuthenticationProvider() {
|
||||
JwtTypeValidator type = new JwtTypeValidator("JWT", "logout+jwt");
|
||||
type.setAllowEmpty(true);
|
||||
Function<ClientRegistration, OAuth2TokenValidator<Jwt>> jwtValidator = (clientRegistration) -> JwtValidators
|
||||
.createDefaultWithValidators(new OidcBackChannelLogoutTokenValidator(clientRegistration));
|
||||
.createDefaultWithValidators(type, new OidcBackChannelLogoutTokenValidator(clientRegistration));
|
||||
this.logoutTokenDecoderFactory = (clientRegistration) -> {
|
||||
String jwkSetUri = clientRegistration.getProviderDetails().getJwkSetUri();
|
||||
if (!StringUtils.hasText(jwkSetUri)) {
|
||||
@ -79,11 +77,7 @@ final class OidcBackChannelLogoutAuthenticationProvider implements Authenticatio
|
||||
null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||
}
|
||||
JOSEObjectTypeVerifier<SecurityContext> typeVerifier = new DefaultJOSEObjectTypeVerifier<>(null,
|
||||
JOSEObjectType.JWT, new JOSEObjectType("logout+jwt"));
|
||||
NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
|
||||
.jwtProcessorCustomizer((processor) -> processor.setJWSTypeVerifier(typeVerifier))
|
||||
.build();
|
||||
NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
|
||||
decoder.setJwtValidator(jwtValidator.apply(clientRegistration));
|
||||
decoder.setClaimSetConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverter());
|
||||
return decoder;
|
||||
|
@ -117,7 +117,7 @@ public final class OidcBackChannelLogoutHandler implements LogoutHandler {
|
||||
}
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
String logout = computeLogoutEndpoint(request, token);
|
||||
MultiValueMap<String, String> body = new LinkedMultiValueMap();
|
||||
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
|
||||
body.add("logout_token", token.getPrincipal().getTokenValue());
|
||||
body.add("_spring_security_internal_logout", "true");
|
||||
HttpEntity<?> entity = new HttpEntity<>(body, headers);
|
||||
|
@ -111,11 +111,6 @@ public final class OidcLogoutConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true, since = "6.2")
|
||||
public B and() {
|
||||
return getBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B builder) throws Exception {
|
||||
if (this.backChannel != null) {
|
||||
|
@ -37,6 +37,7 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
||||
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
@ -49,13 +50,14 @@ import org.springframework.security.oauth2.server.resource.introspection.OpaqueT
|
||||
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.csrf.CsrfException;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
@ -163,7 +165,7 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
|
||||
private AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
|
||||
|
||||
private BearerTokenResolver bearerTokenResolver;
|
||||
private AuthenticationConverter authenticationConverter;
|
||||
|
||||
private JwtConfigurer jwtConfigurer;
|
||||
|
||||
@ -203,22 +205,20 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
|
||||
public OAuth2ResourceServerConfigurer<H> bearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
||||
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
||||
this.bearerTokenResolver = bearerTokenResolver;
|
||||
this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
|
||||
* {@code jwt(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* Sets the {@link AuthenticationConverter} to use.
|
||||
* @param authenticationConverter the authentication converter
|
||||
* @return the {@link OAuth2ResourceServerConfigurer} for further configuration
|
||||
* @since 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public JwtConfigurer jwt() {
|
||||
if (this.jwtConfigurer == null) {
|
||||
this.jwtConfigurer = new JwtConfigurer(this.context);
|
||||
}
|
||||
return this.jwtConfigurer;
|
||||
public OAuth2ResourceServerConfigurer<H> authenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -235,21 +235,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #opaqueToken(Customizer)} or
|
||||
* {@code opaqueToken(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OpaqueTokenConfigurer opaqueToken() {
|
||||
if (this.opaqueTokenConfigurer == null) {
|
||||
this.opaqueTokenConfigurer = new OpaqueTokenConfigurer(this.context);
|
||||
}
|
||||
return this.opaqueTokenConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables opaque bearer token support.
|
||||
* @param opaqueTokenCustomizer the {@link Customizer} to provide more options for the
|
||||
@ -278,16 +263,15 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
|
||||
@Override
|
||||
public void configure(H http) {
|
||||
BearerTokenResolver bearerTokenResolver = getBearerTokenResolver();
|
||||
this.requestMatcher.setBearerTokenResolver(bearerTokenResolver);
|
||||
AuthenticationManagerResolver resolver = this.authenticationManagerResolver;
|
||||
if (resolver == null) {
|
||||
AuthenticationManager authenticationManager = getAuthenticationManager(http);
|
||||
resolver = (request) -> authenticationManager;
|
||||
}
|
||||
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
|
||||
filter.setBearerTokenResolver(bearerTokenResolver);
|
||||
AuthenticationConverter converter = getAuthenticationConverter();
|
||||
this.requestMatcher.setAuthenticationConverter(converter);
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver, converter);
|
||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
filter = postProcess(filter);
|
||||
@ -377,16 +361,29 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
return this.authenticationManagerResolver;
|
||||
}
|
||||
|
||||
BearerTokenResolver getBearerTokenResolver() {
|
||||
if (this.bearerTokenResolver == null) {
|
||||
if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) {
|
||||
this.bearerTokenResolver = this.context.getBean(BearerTokenResolver.class);
|
||||
}
|
||||
else {
|
||||
this.bearerTokenResolver = new DefaultBearerTokenResolver();
|
||||
}
|
||||
AuthenticationConverter getAuthenticationConverter() {
|
||||
if (this.authenticationConverter != null) {
|
||||
return this.authenticationConverter;
|
||||
}
|
||||
return this.bearerTokenResolver;
|
||||
if (this.context.getBeanNamesForType(AuthenticationConverter.class).length > 0) {
|
||||
this.authenticationConverter = this.context.getBean(AuthenticationConverter.class);
|
||||
}
|
||||
else if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) {
|
||||
BearerTokenResolver bearerTokenResolver = this.context.getBean(BearerTokenResolver.class);
|
||||
this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver);
|
||||
}
|
||||
else {
|
||||
this.authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||
}
|
||||
return this.authenticationConverter;
|
||||
}
|
||||
|
||||
BearerTokenResolver getBearerTokenResolver() {
|
||||
AuthenticationConverter authenticationConverter = getAuthenticationConverter();
|
||||
if (authenticationConverter instanceof OAuth2ResourceServerConfigurer.BearerTokenResolverHoldingAuthenticationConverter bearer) {
|
||||
return bearer.bearerTokenResolver;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public class JwtConfigurer {
|
||||
@ -425,17 +422,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
|
||||
* {@code jwt(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ResourceServerConfigurer<H> and() {
|
||||
return OAuth2ResourceServerConfigurer.this;
|
||||
}
|
||||
|
||||
Converter<Jwt, ? extends AbstractAuthenticationToken> getJwtAuthenticationConverter() {
|
||||
if (this.jwtAuthenticationConverter == null) {
|
||||
if (this.context.getBeanNamesForType(JwtAuthenticationConverter.class).length > 0) {
|
||||
@ -574,21 +560,41 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
|
||||
private static final class BearerTokenRequestMatcher implements RequestMatcher {
|
||||
|
||||
private BearerTokenResolver bearerTokenResolver;
|
||||
private AuthenticationConverter authenticationConverter;
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
try {
|
||||
return this.bearerTokenResolver.resolve(request) != null;
|
||||
return this.authenticationConverter.convert(request) != null;
|
||||
}
|
||||
catch (OAuth2AuthenticationException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void setBearerTokenResolver(BearerTokenResolver tokenResolver) {
|
||||
Assert.notNull(tokenResolver, "resolver cannot be null");
|
||||
this.bearerTokenResolver = tokenResolver;
|
||||
void setAuthenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class BearerTokenResolverHoldingAuthenticationConverter implements AuthenticationConverter {
|
||||
|
||||
private final BearerTokenResolver bearerTokenResolver;
|
||||
|
||||
private final AuthenticationConverter authenticationConverter;
|
||||
|
||||
BearerTokenResolverHoldingAuthenticationConverter(BearerTokenResolver bearerTokenResolver) {
|
||||
this.bearerTokenResolver = bearerTokenResolver;
|
||||
BearerTokenAuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||
authenticationConverter.setBearerTokenResolver(bearerTokenResolver);
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication convert(HttpServletRequest request) {
|
||||
return this.authenticationConverter.convert(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user