1
0
mirror of synced 2026-07-12 06:10:02 +00:00

Compare commits

..

201 Commits

Author SHA1 Message Date
Josh Cummings 89c815032c Fix Index Out of Bounds 2022-10-17 14:52:03 -06:00
Josh Cummings ff055cf07a Remote antoraUpdateVersion task from CI 2022-10-17 14:24:13 -06:00
github-actions[bot] b08a06aa76 Release 5.6.8 2022-10-17 18:55:50 +00:00
Marcus Da Coregio 465d80c162 Remove antoreUpdateVersion task from release automation 2022-10-17 15:50:44 -03:00
Marcus Da Coregio 4992e8ce62 Update org.springframework.data to 2021.1.8
Closes gh-12007
2022-10-13 09:24:21 -03:00
Marcus Da Coregio c772daab92 Update org.springframework to 5.3.23
Closes gh-12006
2022-10-13 09:24:20 -03:00
Marcus Da Coregio 45a4a89960 Update hibernate-entitymanager to 5.6.12.Final
Closes gh-12005
2022-10-13 09:24:20 -03:00
Marcus Da Coregio b43c7e927f Update org.eclipse.jetty to 9.4.49.v20220914
Closes gh-12004
2022-10-13 09:24:20 -03:00
Marcus Da Coregio 50d23622d0 Update io.rsocket to 1.1.3
Closes gh-12003
2022-10-13 09:24:20 -03:00
Marcus Da Coregio 2c2603ba0f Update io.projectreactor to 2020.0.24
Closes gh-12001
2022-10-13 09:24:20 -03:00
Marcus Da Coregio f7f53ea2b7 Update jackson-bom to 2.13.4.20221012
Closes gh-11997
2022-10-13 09:22:28 -03:00
Marcus Da Coregio e0f8c711d8 Add default value for cloneOutputDirectory property
Closes gh-11969
2022-10-10 11:00:47 -03:00
Dan Allen e0843aabb1 automatically manage docs version (with collector) 2022-10-05 13:56:22 -05:00
Daniel Garnier-Moiroux 26bb60c567 Add rncToXsd task description to CONTRIBUTING.adoc 2022-10-03 10:09:27 -03:00
Dan Allen c44230ba24 switch to offical Antora plugin for Gradle
- lock version to latest release of Antora 3.1
- rename properties on extension block
- use Node.js version provided by plugin
- remove package.json file
- assign environment variables using environments property on extension block
- use single quotes where possible in build script
- use default setting for log format
2022-09-29 14:05:09 -05:00
Jerome Prinet 8d2fb6858f Update Gradle Enterprise plugin to 3.11.1 2022-09-16 13:14:53 -03:00
Marcus Da Coregio 7756247c3a Simplify checkSamples task
Closes gh-11814
2022-09-16 09:36:12 -03:00
Dan Allen 3387149a0f repurpose 5.6.x branch to provide local docs build
* remove unused workflows, scripts, and configuration (now handled by docs-build branch)
* upgrade Antora to 3.1 (and Node.js to 16)
* tune playbook settings
* reconfigure docs build for local build only
* add patch to support using linked worktree as Antora content source
* remove Antora extensions not needed for local builds
2022-09-12 15:41:12 -05:00
Underground Hill 8b74bf9742 Updated reference to architecture page
In the context of Servlet Authentication page, "Architecture" should probably link to "Servlet Authentication Architecture" page
2022-09-01 09:38:10 -03:00
Marcus Da Coregio 40abf87ae6 Add buildScan to checkRemote
Closes gh-11766
2022-08-30 09:11:08 -03:00
Steve Riesenberg 1c014eb512 Use 6.0.x instead of 3.0.x as default branch 2022-08-24 16:38:27 -05:00
Rob Winch 8c69699458 Remove backportbot.yml
Issue gh-11736
2022-08-23 13:46:32 -05:00
Rob Winch fc10d5fc29 repository=spring-projects/spring-security
Previously the repository used spring-project (missing the s)
2022-08-23 13:30:20 -05:00
Rob Winch c79ebf4edf Setup Forward Merge 2022-08-22 16:19:44 -05:00
Marcus Da Coregio a8d6c1d21f Consistently set AuthenticationEventPublisher in AuthenticationManagerBuilder
Prior to this, the HttpSecurity bean was not consistent with WebSecurityConfigurerAdapter's HttpSecurity because it did not setup a default AuthenticationEventPublisher. This also fixes a problem where the AuthenticationEventPublisher bean would only be considered if there was a UserDetailsService

Closes gh-11449
Closes gh-11726
2022-08-19 09:58:22 -03:00
Steve Riesenberg 7c7f9380c7 Refresh remote JWK when unknown KID error occurs
Closes gh-11621
2022-08-18 16:54:45 -05:00
tinolazreg 888715bbb2 Add tests for unknown KID error
Issue gh-11621
2022-08-18 16:54:45 -05:00
jujunChen 13feb87171 Modify words
- <dependencyManagement> to dependencyManagement
- pom.xml to build.gradle
2022-08-16 14:51:36 -06:00
Rob Winch faf9fb7337 NamespaceLdapAuthenticationProviderTests use Dynamic Port
Closes gh-11710
2022-08-15 15:26:46 -05:00
Rob Winch f33d7253b6 GitHubMilestoneApiTests due_on Uses LocalDate
`GitHubMilestoneApiTests` uses `Instant.now()` for `due_on`. Since
`Instant.now()` is UTC time based,
`isMilestoneDueTodayWhenDueTodayThenTrue` fails when the computer that runs
the test is not the same day as it is in UTC time.

To fix it, `due_on` should be set to an `Instant` based upon the timezone
of the current computer.

Closes gh-11706
2022-08-15 13:04:29 -05:00
github-actions[bot] db74e9d128 Next development version 2022-08-15 16:07:33 +00:00
github-actions[bot] 4559d269e0 Release 5.6.7 2022-08-15 15:25:05 +00:00
Marcus Da Coregio 627809d2dc Update org.springframework.data to 2021.1.6
Closes gh-11686
2022-08-10 14:52:51 -03:00
Marcus Da Coregio 4b1d7e9479 Update org.springframework to 5.3.22
Closes gh-11685
2022-08-10 14:52:51 -03:00
Marcus Da Coregio d9980a4dfe Update jsonassert to 1.5.1
Closes gh-11684
2022-08-10 14:52:51 -03:00
Marcus Da Coregio 8eb7e589eb Update hibernate-entitymanager to 5.6.10.Final
Closes gh-11683
2022-08-10 14:52:51 -03:00
Marcus Da Coregio 0d7dce9d71 Update org.eclipse.jetty to 9.4.48.v20220622
Closes gh-11682
2022-08-10 14:52:51 -03:00
Marcus Da Coregio da09788be9 Update io.projectreactor to 2020.0.22
Closes gh-11680
2022-08-10 14:52:51 -03:00
Marcus Da Coregio ead587c597 Consistently handle RequestRejectedException if it is wrapped
Closes gh-11645
2022-08-09 08:32:42 -03:00
Steve Riesenberg 02459919cc Skip workflows on forks of spring-security 2022-07-28 15:13:56 -05:00
Steve Riesenberg 57d212ddca Use cache and user.name system property on Windows 2022-07-28 15:13:55 -05:00
Steve Riesenberg 539b17f6da Only run prerequisites job if on upstream repo 2022-07-28 15:13:54 -05:00
Steve Riesenberg 37e1ad27fe Simplify dependency graph 2022-07-28 15:13:53 -05:00
Steve Riesenberg 043fdd6f03 Use Spring Gradle Build Action
Closes gh-11630
2022-07-28 15:13:52 -05:00
Steve Riesenberg 3234e05085 Polish gh-11367 2022-07-28 15:13:51 -05:00
naveen f957e3c051 Set permissions for GitHub actions
Restrict the GitHub token permissions only to the required ones; this
way, even if the attackers will succeed in compromising your workflow,
they won’t be able to do much.

- Included permissions for the action.

https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions

https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs

Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests
https://securitylab.github.com/research/github-actions-preventing-pwn-requests/

Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>

Closes gh-11367
2022-07-28 15:13:51 -05:00
Marcus Da Coregio d66ad22652 Add Deprecated annotation to WebSecurity#securityInterceptor
Closes gh-11634
2022-07-27 14:32:44 -03:00
Rob Winch 7a860e1568 Fix Snapshot Sources/Javadoc
This commit merges a workaround to an issue in JFrog's Gradle plugin
which causes SNAPSHOT javadoc and sources to become out of sync and thus
prevents users from being able to download either.

Closes gh-10602
2022-07-26 16:26:31 -05:00
Desmond Silveira 0d3c3c676d "Well-Know" should be "Well-Known" 2022-07-26 15:45:27 -05:00
Yuriy Savchenko 0f64d4c091 Add Kotlin example for WebTestClient setup docs
Closes gh-9998
2022-07-22 14:04:16 -03:00
Josh Cummings 56a6133b20 Merge Same-named Attribute Elements
Closes gh-11042
2022-07-20 18:43:25 -06:00
Steve Riesenberg aaf20e7b61 Build only on branches
Issue gh-11480
2022-07-18 11:47:25 -05:00
Steve Riesenberg 148756076c Backport release automation and github actions
Closes gh-11501
2022-07-13 15:51:25 -05:00
Steve Riesenberg 6f321a27c4 Fix inconsistency in hasProperty check 2022-07-13 15:51:25 -05:00
Steve Riesenberg 539443b4be Add GitHubReleasePlugin with createGitHubRelease task
Issue gh-10456
Issue gh-10457
2022-07-13 15:51:24 -05:00
Josh Cummings 28424f8ae5 Correct input validation for 31 rounds
Closes gh-11470
2022-07-11 14:51:51 -06:00
Rob Winch a7d21f1b34 Document sagan Release tasks require read:org scope
Closes gh-11423
2022-06-21 14:49:38 -05:00
Joe Grandja d3a024786b Next Development Version 2022-06-20 15:05:30 -04:00
Joe Grandja fa4c5449e7 Release 5.6.6 2022-06-20 14:50:24 -04:00
Joe Grandja 2a3845a7ed Update org.opensaml:opensaml-core4 to 4.1.1
Closes gh-11420
2022-06-20 14:50:24 -04:00
Joe Grandja ff96a7b5ad Update spring-ldap-core to 2.3.8.RELEASE
Closes gh-11419
2022-06-20 14:41:13 -04:00
Joe Grandja c37ff42234 Update org.springframework.data to 2021.1.5
Closes gh-11418
2022-06-20 14:41:10 -04:00
Joe Grandja 0a00d84838 Update org.springframework to 5.3.21
Closes gh-11417
2022-06-20 14:41:08 -04:00
Joe Grandja 96c6751a1d Update hibernate-entitymanager to 5.6.9.Final
Closes gh-11416
2022-06-20 14:41:05 -04:00
Joe Grandja 8ee9c32788 Update io.projectreactor to 2020.0.20
Closes gh-11414
2022-06-20 14:41:00 -04:00
Joe Grandja 7a5fb9eaf7 Update jackson-bom to 2.13.3
Closes gh-11411
2022-06-20 14:40:53 -04:00
Joe Grandja 8cbb972cef Add dependency update exclusion for spring-javaformat-checkstyle 2022-06-20 14:27:40 -04:00
Josh Cummings 539a11d0a4 Encode postLogoutRedirectUri query params
Closes gh-11379
2022-06-16 16:13:42 -06:00
Zhivko Delchev e97c5a533b Reverse content type check
When MultipartFormData is enabled currently the CsrfWebFilter compares
the content-type header against MULTIPART_FORM_DATA MediaType which
leads to NullPointerExecption when there is no content-type header.
This commit reverse the check to compare the MULTIPART_FORM_DATA
MediaType against the content-type which contains null check and avoids
the exception.

closes gh-11204
Closes gh-11205
2022-06-06 15:47:35 -05:00
shirohoo e0fa644b08 Fix typo in BasicLookupStrategy Javadoc
Closes gh-11336
2022-06-06 14:16:28 -05:00
Rob Winch 592db9180d Enable BackportBot on 5.6.x 2022-06-06 14:16:28 -05:00
André Luis Gomes aca3fc2412 Update opaque-token.adoc
Fixing yaml sample in Servlet and Reactive pages
2022-06-01 08:51:44 -03:00
Claudio Consolmagno 07f9afe057 Use 'md:' prefix in EntityDescriptor XML
Create the EntityDescriptor object with
EntityDescriptor.DEFAULT_ELEMENT_NAME instead of
EntityDescriptor.ELEMENT_QNAME. That ensures the EntityDescriptor tag
is marshalled to xml with the 'md:' prefix, consistent with all other
metadata tags.

Closes #11283
2022-05-31 17:11:02 -06:00
Josh Cummings d7077b441a Correct access(String) reference
Closes gh-11280
2022-05-27 15:00:15 -06:00
Josh Cummings 101f11ba94 Improve ContextConfiguration Docs
Point to updated Spring Reference

Issue gh-10934
2022-05-27 13:12:56 -06:00
Josh Cummings 18b903f6e3 Polish ExtendWith Docs
Use spring-framework-reference-url placeholder

Issue gh-10934
2022-05-27 13:12:56 -06:00
nor-ek 038266a94f Update JUnit 5 annotations in documentation
- replace Before with BeforeEach
- replace RunWith with ExtendWith

Closes gh-10934
2022-05-27 13:12:55 -06:00
Evgeniy Cheban cf559ab224 Some Security Expressions cause NPE when used within Query annotation
Added trustResolver, roleHierarchy, permissionEvaluator, defaultRolePrefix
fields to SecurityEvaluationContextExtension.

Closes gh-11196
Closes gh-11290
2022-05-26 17:44:28 -05:00
Juny Tse 649428b49a Use Base64 encoder with no CRLF in output for SAML 2.0 messages
Closes gh-11262
2022-05-25 12:06:27 -06:00
Steve Riesenberg 0355e960d7 Next development version 2022-05-18 11:52:05 -05:00
Steve Riesenberg fdad14af63 Release 5.6.5 2022-05-18 11:03:25 -05:00
Rob Winch 077c9e0b3e StrictHttpFirewall allows CJKV characters
Closes gh-11264
2022-05-18 08:56:57 -05:00
Rob Winch dc648cf79f Next Developement Version 2022-05-16 11:51:06 -05:00
Rob Winch c2d2914a4f Release 5.6.4 2022-05-16 11:36:26 -05:00
Josh Cummings a40f73521c Improve Upgrading 2022-05-16 11:36:26 -05:00
Rob Winch 70863952ae AntRegexRequestMatcher Optimization
Closes gh-11234
2022-05-16 10:17:44 -05:00
Rob Winch af95be34c6 Extract rejectNonPrintableAsciiCharactersInFieldName
Closes gh-11234
2022-05-16 10:17:44 -05:00
Rob Winch 71478c2534 Update org.springframework.data to 2021.1.4
Closes gh-11210
2022-05-13 09:28:59 -05:00
Rob Winch b289d12aad Update org.springframework to 5.3.20
Closes gh-11209
2022-05-13 09:28:56 -05:00
Rob Winch e2361c5c79 Update io.projectreactor to 2020.0.19
Closes gh-11207
2022-05-13 09:28:52 -05:00
Rob Winch 8b9c8ca96c Update mockk to 1.12.4
Closes gh-11206
2022-05-13 09:28:49 -05:00
Marcus Da Coregio 44e672d969 Use properties in the checkSamples job
Issue gh-10344
2022-05-11 16:13:34 -03:00
Marcus Da Coregio 330f0f050d Add initScripts and projectProperties to IncludeCheckRemotePlugin
Issue gh-10344
2022-05-11 16:13:34 -03:00
Marcus Da Coregio e45dcb3ab2 Update copyright headers
Issue gh-10956
2022-05-06 14:18:42 -03:00
Marcus Da Coregio d3a451fffb Fix mvcMatchers overriding previous paths
Closes gh-10956
2022-05-06 14:18:36 -03:00
Marcus Da Coregio 9d378103b0 Fix setServletContext not being called for AuthorizationManagerWebInvocationPrivilegeEvaluator
Issue gh-10908
2022-04-25 09:43:50 -03:00
Marcus Da Coregio 2031f101dc Exclude duplicate issues from changelog
Closes gh-11154
2022-04-20 09:07:16 -03:00
Marcus Da Coregio 2a2c2dd209 Next development version 2022-04-18 13:27:01 -03:00
Marcus Da Coregio fa0e06ebdc Release 5.6.3 2022-04-18 11:59:42 -03:00
Marcus Da Coregio 6724627b50 Update spring-ldap-core to 2.3.7.RELEASE
Closes gh-11127
2022-04-18 11:45:27 -03:00
Marcus Da Coregio 4aab7b06a9 Update org.springframework.data to 2021.1.3
Closes gh-11126
2022-04-18 11:45:24 -03:00
Marcus Da Coregio d0d4d58c48 Update org.springframework to 5.3.19
Closes gh-11125
2022-04-18 11:45:22 -03:00
Marcus Da Coregio 29be60d035 Update hibernate-entitymanager to 5.6.8.Final
Closes gh-11124
2022-04-18 11:45:19 -03:00
Marcus Da Coregio 5024103b07 Update org.eclipse.jetty to 9.4.46.v20220331
Closes gh-11123
2022-04-18 11:45:17 -03:00
Marcus Da Coregio d0327807a7 Update org.aspectj to 1.9.9.1
Closes gh-11122
2022-04-18 11:45:14 -03:00
Marcus Da Coregio f880f1ba26 Update io.rsocket to 1.1.2
Closes gh-11121
2022-04-18 11:45:12 -03:00
Marcus Da Coregio 71dafc0c06 Update io.projectreactor to 2020.0.18
Closes gh-11119
2022-04-18 11:45:07 -03:00
Marcus Da Coregio 7d9357b871 Update mockk to 1.12.3
Closes gh-11118
2022-04-18 11:45:05 -03:00
Marcus Da Coregio 0b02bbecd1 Update jackson-bom to 2.13.2.20220328
Closes gh-11115
2022-04-18 11:44:57 -03:00
Marcus Da Coregio 932a5cc8b4 Update logback-classic to 1.2.11
Closes gh-11114
2022-04-18 11:44:55 -03:00
Simone Giannino e4a321511a Update saganCreateRelease property referenceDocUrl
- Updated saganCreateRelease task with the new referenceDocUrl for reference documentation

Closes gh-11016
2022-04-01 13:08:18 -03:00
Johannes Graf 4ee5800ec9 use okta as registration id
looks like `ping` is some registration id used in the past.

Closes gh-11034
2022-03-30 14:41:03 -06:00
Marcus Da Coregio c67632225d Use ServletContext in AuthorizationManagerWebInvocationPrivilegeEvaluator
Closes gh-10908
2022-03-28 10:13:40 -03:00
Rob Winch 6e45a376cd Remove "Hi ... there" From Docs
Close gh-10963
2022-03-11 13:42:38 -06:00
Marcus Da Coregio 70b67cd2f1 AuthorizationManagerWebInvocationPrivilegeEvaluator grant access when AuthorizationManager abstains
Closes gh-10950
2022-03-09 15:22:21 -03:00
Josh Cummings 304e89041c Polish Formatting
Issue gh-10799
2022-03-02 16:40:13 -07:00
Sander van Schouwenburg f1a76efc2d Preserve order of RelyingPartRegistration credentials
Issue gh-10799
2022-03-02 16:40:13 -07:00
Josh Cummings 963251314b Replace Apache Commons Base64 Decoding
Issue gh-10923
2022-03-02 16:40:11 -07:00
Josh Cummings ee061f3659 Use RFC2045 Encoding for SAML 2.0 Logout
Closes gh-10923
2022-03-02 16:39:31 -07:00
Talerngpong Virojwutikul 440ffce2eb Update PasswordEncoder declaration
Closes gh-10910
2022-03-01 07:50:55 -07:00
Filip Hanik 47871562ca Change HashSet to LinkedHashSet
For various RelyingPartyRegistration.credentials to preserve order of insertion.

Issue gh-10799
2022-02-28 15:02:03 -07:00
Josh Cummings f0c548cee7 Invert Log Messages
Closes gh-10909
2022-02-28 13:17:01 -07:00
Marcus Da Coregio 1a32b399e6 Next development version 2022-02-21 10:49:06 -03:00
Marcus Da Coregio e9f3da94fc Release 5.6.2 2022-02-21 10:04:41 -03:00
Marcus Da Coregio 4fb6f936a7 Update spring-ldap-core to 2.3.6.RELEASE
Closes gh-10877
2022-02-21 09:20:57 -03:00
Marcus Da Coregio c431b5479e Update org.springframework.data to 2021.1.2
Closes gh-10876
2022-02-21 09:20:54 -03:00
Marcus Da Coregio fc03950afd Update org.springframework to 5.3.16
Closes gh-10875
2022-02-21 09:20:52 -03:00
Marcus Da Coregio 516b5fed4a Update org.slf4j to 1.7.36
Closes gh-10874
2022-02-21 09:20:49 -03:00
Marcus Da Coregio 165e29e585 Update hibernate-entitymanager to 5.6.5.Final
Closes gh-10873
2022-02-21 09:20:47 -03:00
Marcus Da Coregio 0be3e86b21 Update org.eclipse.jetty to 9.4.45.v20220203
Closes gh-10872
2022-02-21 09:20:44 -03:00
Marcus Da Coregio 96d229a6d1 Update org.aspectj to 1.9.8
Closes gh-10871
2022-02-21 09:20:42 -03:00
Marcus Da Coregio 5098cad9cf Update io.spring.javaformat to 0.0.31
Closes gh-10870
2022-02-21 09:20:40 -03:00
Marcus Da Coregio 883c480af0 Update r2dbc-h2 to 0.8.5.RELEASE
Closes gh-10869
2022-02-21 09:20:37 -03:00
Marcus Da Coregio 0f83e40427 Update io.projectreactor to 2020.0.16
Closes gh-10867
2022-02-21 09:20:32 -03:00
Marcus Da Coregio ad6ef6e4c7 Update mockk to 1.12.2
Closes gh-10866
2022-02-21 09:20:30 -03:00
Marcus Da Coregio 94201e46f1 Update logback-classic to 1.2.10
Closes gh-10865
2022-02-21 09:20:27 -03:00
Rob Winch 910e198cee Add .sdkmanrc 2022-02-18 13:48:26 -06:00
Talerngpong Virojwutikul 45a88fc391 add Kotlin examples for Spring Data Integration of servlet application 2022-02-18 08:49:27 -03:00
giger85 8f01efb9e3 Replace StringUtils class completely
Issue gh-9925
Closes gh-10805
2022-02-10 17:50:07 +01:00
Josh Cummings f53c65b3a0 Polish ignoring() log messaging
- Public API remains unchanged

Issue gh-9334
2022-02-07 15:07:29 -07:00
Manuel Jordan 0be772ff5b Print ignore message DefaultSecurityFilterChain
When either `web.ignoring().mvcMatchers(...)` or
`web.ignoring().antMatchers(...)` methods are used, for all their
variations, the DefaultSecurityFilterChain class now indicates
correctly through its ouput what paths are ignored according the
`ignoring()` settings.

Closes gh-9334
2022-02-07 15:07:29 -07:00
Rob Winch ac990afa5d Document Authorize HTTP Requests for Reactive Security
Closes gh-10801
2022-02-03 13:47:35 -06:00
Ken Dombeck 55cccbf727 Fix broken link to SAML2 login example 2022-02-03 10:20:45 -06:00
Eleftheria Stein a095ea75a2 Fix typo in getting started docs
Closes gh-10736
2022-02-02 10:52:54 +01:00
Marcus Da Coregio a041e7c943 RequestMatcherDelegatingWebInvocationPrivilegeEvaluator doesn't provided access to the ServletContext
Closes gh-10779
2022-01-31 09:50:17 -03:00
Rob Winch 4f3072b3d9 Exclude javax from hibernate dependency
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch 13c467734a Remove javax.transaction
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch c01b2b946b Additional removal of javax.inject
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch 549f9dab64 dependencies jakarta.transaction-api
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch 58090c37ea jsr250-api -> jakarta.annotation-api
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch 38344e8de6 javax.servlet.jsp-api -> jakarta.servlet.jsp-api
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch 6f319f0b13 javax.servlet.jsp.jstl-api -> jakarta.servlet.jsp.jstl-api
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch 4e71b26ea4 Exclude javax from cas-client-core
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch 04f3bbcefa javax.xml.bind:jaxb-api -> jakarta.xml.bind:jakarta.xml.bind-api
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch c67ee6f2a8 javax.servlet:javax.servlet-api -> jakarta.servlet:jakarta.servlet-api
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch 4b590ce31f Remove javax.inject
Issue gh-10501
2022-01-19 15:32:12 -06:00
Rob Winch 5902b46e9b Remove jcl-over-slf4j
Issue gh-10499

# Conflicts:
#	dependencies/spring-security-dependencies.gradle
2022-01-19 15:32:01 -06:00
Rob Winch 62449d6fa2 Remove commons-logging
Closes gh-10499
2022-01-19 15:31:22 -06:00
Rob Winch aa06088077 Add CheckProhibitedDependenciesLifecyclePlugin
Issue gh-10501
2022-01-19 15:30:34 -06:00
Rob Winch 2a60776c8a Add CheckClasspathForProhibitedDependencies
Issues gh-10499 gh-10501
2022-01-19 15:30:34 -06:00
Rob Winch f411ecada2 CheckAntoraVersionTask has optional properties 2022-01-18 14:29:39 -06:00
Rob Winch 8eeacf4a36 Fix Antora for Milestone & RC
- Verify Antora display_version
- Run workflow for tags
- Allow run workflow manually

Issue gh-10765
2022-01-18 14:20:47 -06:00
Josh Cummings 20c252982e Remove SAML 2.0 Logout Default
Closes gh-10607
2022-01-14 15:29:50 -07:00
Josh Cummings 6c5ac0d8ec Use noNullElements
Collection#contains(null) does not work for all collection types

Closes gh-10703
2022-01-14 15:09:21 -07:00
Marcus Da Coregio e1cb375fbf Make source code compatible with JDK 8
Closes gh-10695
2022-01-12 16:39:50 -03:00
Marcus Da Coregio e7e3f06044 Fix @since tag
Issue gh-10590, gh-10554
2022-01-06 13:22:13 -03:00
Marcus Da Coregio 994e93741b Configure WebInvocationPrivilegeEvaluator bean for multiple filter chains
Closes gh-10554
2022-01-05 14:06:47 -03:00
Marcus Da Coregio 04e1a11e35 Add RequestMatcherEntry 2022-01-05 14:06:47 -03:00
Marcus Da Coregio 547056d5cc Introduce AuthorizationManagerWebInvocationPrivilegeEvaluator
Closes gh-10590
2022-01-05 14:06:47 -03:00
Rob Winch 1fa35fb9a8 Antora prerelease: true for milestone and rc 2022-01-05 10:00:56 -06:00
Rob Winch a49914e631 Update RELEASE.adoc for antora.yml 2022-01-04 15:52:05 -06:00
Rob Winch 783a43ea35 Add CheckAntoraVersionPlugin 2022-01-04 15:52:05 -06:00
Rob Winch 07a176d11e Update antora to 5.6.2 2022-01-04 15:52:05 -06:00
Josh Cummings c664fbc1a3 Support No SingleLogoutServiceLocation
Closes gh-10674
2022-01-03 13:38:47 -07:00
Steve Riesenberg af412c4d65 Next Development Version 2021-12-20 15:24:46 -06:00
Steve Riesenberg e38bf6e554 Release 5.6.1 2021-12-20 14:14:55 -06:00
Steve Riesenberg 624e0da669 Update spring-ldap-core to 2.3.5.RELEASE
Closes gh-10659
2021-12-20 12:28:54 -06:00
Steve Riesenberg b28aa6c647 Update org.springframework to 5.3.14
Closes gh-10658
2021-12-20 12:28:52 -06:00
Steve Riesenberg 9e83b4be25 Update junit-bom to 5.8.2
Closes gh-10656
2021-12-20 12:28:47 -06:00
Steve Riesenberg e9854c91ef Update org.jetbrains.kotlin to 1.5.32
Closes gh-10655
2021-12-20 12:28:45 -06:00
Steve Riesenberg 0345e29afb Update cas-client-core to 3.6.4
Closes gh-10654
2021-12-20 12:28:43 -06:00
Steve Riesenberg 8bd5795f8e Update hibernate-entitymanager to 5.6.3.Final
Closes gh-10653
2021-12-20 12:28:41 -06:00
Steve Riesenberg 4fbc98dcd2 Update io.projectreactor to 2020.0.14
Closes gh-10651
2021-12-20 12:28:36 -06:00
Steve Riesenberg 44cdbd6cf3 Update mockk to 1.12.1
Closes gh-10650
2021-12-20 12:28:34 -06:00
Steve Riesenberg a9af8c4128 Update jackson-bom to 2.13.1
Closes gh-10647
2021-12-20 12:28:28 -06:00
Steve Riesenberg 28c81af788 Update logback-classic to 1.2.9
Closes gh-10646
2021-12-20 12:28:26 -06:00
Steve Riesenberg 3a956daf0c Exclude minor version bump 2021-12-20 12:16:04 -06:00
Marcus Da Coregio 9c245865d7 Point to samples on 5.6.x branch 2021-12-10 14:38:24 -03:00
Guirong Hu 86ed937a47 Fix the bug that the custom GrantedAuthority comparison fails
Closes gh-10566
2021-12-08 08:51:54 -03:00
Steve Riesenberg 32ec8c3ae4 Fix Reactive OAuth2 Kotlin DSL examples
Closes gh-10580
2021-12-07 13:58:24 +01:00
Steve Riesenberg c7ffd2513a Update copyright year
Issue gh-10557
2021-12-01 17:36:19 -06:00
Steve Riesenberg b3e0f167ff Fix case sensitive headers comparison
Closes gh-10557
2021-12-01 15:01:06 -06:00
Jonas Erbe 8c063f8ccb Fix JwtClaimValidator wrong error code
Previously JwtClaimValidator returned the invalid_request error on claim validation failure.
But validators have to return invalid_token errors on failure according to:
https://datatracker.ietf.org/doc/html/rfc6750#section-3.1.
Also see gh-10337

Closes gh-10337
2021-11-29 12:13:24 -07:00
Henning Poettker f1ca42e501 Fix return type for NoOpPasswordEncoder bean in documentation 2021-11-23 14:14:05 -03:00
Lars Grefer 719149f01d Remove usages of Gradle's jcenter() repository
Closes gh-10253
2021-11-22 09:38:49 -03:00
Lars Grefer ccd30607a9 Fix Gradle Deprecation Warnings 2021-11-22 09:38:44 -03:00
Dávid Kováč aa1ef46d84 Update clockSkew javadoc according to implementation
Closes gh-10174
2021-11-19 13:33:05 +01:00
Josh Cummings 16a21264d0 Polish AuthRequestConverter Sample Doc
Issue gh-10364
2021-11-18 13:36:31 -07:00
Norbert Nowak 1c0f092176 Fix AuthnRequestConverter Sample Typos
Closes gh-10364
2021-11-18 13:26:53 -07:00
Jeff Maxwell 32d79f3f4e Fix setJWTClaimSetJWSKeySelector Typo
Closes gh-10504
2021-11-16 15:33:42 -07:00
Jeff Maxwell 088a24cf59 Fix jwtDecoder Documentation Usage
Closes gh-10505
2021-11-16 15:18:42 -07:00
505 changed files with 3145 additions and 27551 deletions
-20
View File
@@ -1,20 +0,0 @@
{
"index_name": "security-docs",
"start_urls": [
"https://docs.spring.io/spring-security/reference/"
],
"selectors": {
"lvl0": {
"selector": "//nav[@class='crumbs']//li[@class='crumb'][last()-1]",
"type": "xpath",
"global": true,
"default_value": "Home"
},
"lvl1": ".doc h1",
"lvl2": ".doc h2",
"lvl3": ".doc h3",
"lvl4": ".doc h4",
"text": ".doc p, .doc td.content, .doc th.tableblock"
}
}
-20
View File
@@ -1,20 +0,0 @@
#!/bin/bash
HOST="$1"
HOST_PATH="$2"
SSH_PRIVATE_KEY="$3"
SSH_KNOWN_HOST="$4"
if [ "$#" -ne 4 ]; then
echo -e "not enough arguments USAGE:\n\n$0 \$HOST \$HOST_PATH \$SSH_PRIVATE_KEY \$SSH_KNOWN_HOSTS \n\n" >&2
exit 1
fi
# Use a non-default path to avoid overriding when testing locally
SSH_PRIVATE_KEY_PATH=~/.ssh/github-actions-docs
install -m 600 -D /dev/null "$SSH_PRIVATE_KEY_PATH"
echo "$SSH_PRIVATE_KEY" > "$SSH_PRIVATE_KEY_PATH"
echo "$SSH_KNOWN_HOST" > ~/.ssh/known_hosts
rsync --delete -avze "ssh -i $SSH_PRIVATE_KEY_PATH" docs/build/site/ "$HOST:$HOST_PATH"
rm -f "$SSH_PRIVATE_KEY_PATH"
@@ -1,21 +0,0 @@
#!/bin/bash
###
# Docs
# config.json https://docsearch.algolia.com/docs/config-file
# Run the crawler https://docsearch.algolia.com/docs/run-your-own/#run-the-crawl-from-the-docker-image
### USAGE
if [ "$#" -ne 3 ]; then
echo -e "not enough arguments USAGE:\n\n$0 \$ALGOLIA_APPLICATION_ID \$ALGOLIA_API_KEY \$CONFIG_FILE\n\n" >&2
exit 1
fi
# Script Parameters
APPLICATION_ID=$1
API_KEY=$2
CONFIG_FILE=$3
#### Script
script_dir=$(dirname $0)
docker run -e "APPLICATION_ID=$APPLICATION_ID" -e "API_KEY=$API_KEY" -e "CONFIG=$(cat $CONFIG_FILE | jq -r tostring)" algolia/docsearch-scraper
-20
View File
@@ -1,20 +0,0 @@
name: Update Algolia Index
on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
permissions:
contents: read
jobs:
update:
name: Update Algolia Index
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- name: Checkout Source
uses: actions/checkout@v2
- name: Update Index
run: ${GITHUB_WORKSPACE}/.github/actions/algolia-docsearch-scraper.sh "${{ secrets.ALGOLIA_APPLICATION_ID }}" "${{ secrets.ALGOLIA_WRITE_API_KEY }}" "${GITHUB_WORKSPACE}/.github/actions/algolia-config.json"
-33
View File
@@ -1,33 +0,0 @@
name: Backport Bot
on:
issues:
types: [labeled]
pull_request:
types: [labeled]
push:
branches:
- '*.x'
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
permissions:
contents: read
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Download BackportBot
run: wget https://github.com/spring-io/backport-bot/releases/download/latest/backport-bot-0.0.1-SNAPSHOT.jar
- name: Backport
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_EVENT: ${{ toJSON(github.event) }}
run: java -jar backport-bot-0.0.1-SNAPSHOT.jar --github.accessToken="$GITHUB_TOKEN" --github.event_name "$GITHUB_EVENT_NAME" --github.event "$GITHUB_EVENT"
@@ -98,13 +98,15 @@ jobs:
- name: Check samples project
env:
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
SAMPLES_INIT_SCRIPT: ${{ github.workspace }}/build/includeRepo/spring-security-ci.gradle
SAMPLES_DIR: ../spring-security-samples
VERSION: ${{ needs.prerequisites.outputs.project_version }}
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew publishMavenJavaPublicationToLocalRepository
./gradlew checkSamples -PsamplesInitScript="$SAMPLES_INIT_SCRIPT" -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" --stacktrace
./gradlew cloneSamples -PcloneOutputDirectory="$SAMPLES_DIR"
./gradlew --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$VERSION" :runAllTests
check_tangles:
name: Check for Package Tangles
needs: [ prerequisites ]
@@ -269,7 +271,6 @@ jobs:
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
echo "Updating $REPO@$VERSION to next snapshot version."
./gradlew :updateToSnapshotVersion
./gradlew :spring-security-docs:antoraUpdateVersion
git commit -am "Next development version"
git push
perform_post_release:
-34
View File
@@ -1,34 +0,0 @@
name: Build & Deploy Reference
on:
repository_dispatch:
types: request-build-reference
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
permissions:
contents: read
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Cleanup Gradle Cache
# Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
# Restoring these files from a GitHub Actions cache might cause problems for future builds.
run: |
rm -f /home/runner/.gradle/caches/modules-2/modules-2.lock
rm -f /home/runner/.gradle/caches/modules-2/gc.properties
- name: Build with Gradle
run: ./gradlew :spring-security-docs:antora --stacktrace
- name: Deploy
run: ${GITHUB_WORKSPACE}/.github/actions/algolia-deploy.sh "${{ secrets.DOCS_USERNAME }}@${{ secrets.DOCS_HOST }}" "/opt/www/domains/spring.io/docs/htdocs/spring-security/reference/" "${{ secrets.DOCS_SSH_KEY }}" "${{ secrets.DOCS_SSH_HOST_KEY }}"
@@ -64,7 +64,6 @@ jobs:
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
./gradlew :updateProjectVersion
./gradlew :spring-security-docs:antoraUpdateVersion
updatedVersion=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
git commit -am "Release $updatedVersion"
git tag $updatedVersion
+9 -2
View File
@@ -43,9 +43,12 @@ If you're considering anything more than correcting a typo or fixing a minor bug
If you have not previously done so, please fill out and submit the https://cla.pivotal.io/sign/spring[Contributor License Agreement].
= Create your branch from main
= Create your branch from oldest maintenance branch
Create your topic branch to be submitted as a pull request from main. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting.
Create your topic branch to be submitted as a pull request from the oldest impacted and supported maintenance branch.
You can find the supported versions by looking at the https://github.com/spring-projects/spring-security/milestones[milestones page].
Switch to a branch named `<major>.<minor>.x` from the smallest milestone in the format of `<major>.<minor>.<patch>(-<prerelease>)`.
The spring team will ensure the code gets merged forward into additional branches.
= Use short branch names
@@ -133,6 +136,10 @@ Search the codebase to find related unit tests and add additional `@Test` method
Update the https://www.relaxng.org[RELAX NG] schema `spring-security-x.y.rnc` instead of `spring-security-x.y.xsd` if you contribute changes to supported XML configuration. The XML schema file can be generated the following Gradle task:
----
./gradlew :spring-security-config:rncToXsd
----
Changes to the XML schema will be overwritten by the Gradle build task.
= Squash commits
@@ -42,7 +42,7 @@ import org.springframework.security.acls.domain.AuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PermissionFactory;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.AccessControlEntry;
@@ -51,7 +51,6 @@ import org.springframework.security.acls.model.AclCache;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityGenerator;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
@@ -110,8 +109,6 @@ public class BasicLookupStrategy implements LookupStrategy {
private final AclAuthorizationStrategy aclAuthorizationStrategy;
private ObjectIdentityGenerator objectIdentityGenerator;
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
private final AclCache aclCache;
@@ -165,7 +162,6 @@ public class BasicLookupStrategy implements LookupStrategy {
this.aclCache = aclCache;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.grantingStrategy = grantingStrategy;
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
this.aclClassIdUtils = new AclClassIdUtils();
this.fieldAces.setAccessible(true);
this.fieldAcl.setAccessible(true);
@@ -492,11 +488,6 @@ public class BasicLookupStrategy implements LookupStrategy {
}
}
public final void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
Assert.notNull(objectIdentityGenerator, "objectIdentityGenerator cannot be null");
this.objectIdentityGenerator = objectIdentityGenerator;
}
public final void setConversionService(ConversionService conversionService) {
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
}
@@ -578,8 +569,7 @@ public class BasicLookupStrategy implements LookupStrategy {
// target id type, e.g. UUID.
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator
.createObjectIdentity(identifier, rs.getString("class"));
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"), identifier);
Acl parentAcl = null;
long parentAclId = rs.getLong("parent_object");
@@ -31,12 +31,11 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityGenerator;
import org.springframework.security.acls.model.Sid;
import org.springframework.util.Assert;
@@ -82,8 +81,6 @@ public class JdbcAclService implements AclService {
private AclClassIdUtils aclClassIdUtils;
private ObjectIdentityGenerator objectIdentityGenerator;
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
this(new JdbcTemplate(dataSource), lookupStrategy);
}
@@ -94,7 +91,6 @@ public class JdbcAclService implements AclService {
this.jdbcOperations = jdbcOperations;
this.lookupStrategy = lookupStrategy;
this.aclClassIdUtils = new AclClassIdUtils();
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
}
@Override
@@ -109,7 +105,7 @@ public class JdbcAclService implements AclService {
String javaType = rs.getString("class");
Serializable identifier = (Serializable) rs.getObject("obj_id");
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
return this.objectIdentityGenerator.createObjectIdentity(identifier, javaType);
return new ObjectIdentityImpl(javaType, identifier);
}
@Override
@@ -169,11 +165,6 @@ public class JdbcAclService implements AclService {
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
}
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
Assert.notNull(objectIdentityGenerator, "objectIdentityGenerator cannot be null");
this.objectIdentityGenerator = objectIdentityGenerator;
}
protected boolean isAclClassIdSupported() {
return this.aclClassIdSupported;
}
@@ -318,13 +318,4 @@ public abstract class AbstractBasicLookupStrategyTests {
assertThat(((GrantedAuthoritySid) result).getGrantedAuthority()).isEqualTo("sid");
}
@Test
public void setObjectIdentityGeneratorWhenNullThenThrowsIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.strategy.setObjectIdentityGenerator(null))
.withMessage("objectIdentityGenerator cannot be null");
// @formatter:on
}
}
@@ -45,7 +45,6 @@ import org.springframework.security.acls.model.Sid;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
@@ -171,26 +170,6 @@ public class JdbcAclServiceTests {
.isEqualTo(UUID.fromString("25d93b3f-c3aa-4814-9d5e-c7c96ced7762"));
}
@Test
public void setObjectIdentityGeneratorWhenNullThenThrowsIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.aclServiceIntegration.setObjectIdentityGenerator(null))
.withMessage("objectIdentityGenerator cannot be null");
}
@Test
public void findChildrenWhenObjectIdentityGeneratorSetThenUsed() {
this.aclServiceIntegration
.setObjectIdentityGenerator((id, type) -> new ObjectIdentityImpl(type, "prefix:" + id));
ObjectIdentity objectIdentity = new ObjectIdentityImpl("location", "US");
this.aclServiceIntegration.setAclClassIdSupported(true);
List<ObjectIdentity> objectIdentities = this.aclServiceIntegration.findChildren(objectIdentity);
assertThat(objectIdentities.size()).isEqualTo(1);
assertThat(objectIdentities.get(0).getType()).isEqualTo("location");
assertThat(objectIdentities.get(0).getIdentifier()).isEqualTo("prefix:US-PAL");
}
class MockLongIdDomainObject {
private Object id;
+4
View File
@@ -27,3 +27,7 @@ sourceSets.test.aspectj.srcDir "src/test/java"
sourceSets.test.java.srcDirs = files()
compileAspectj.ajcOptions.outxmlfile = "META-INF/aop.xml"
aspectj {
version = aspectjVersion
}
+10 -14
View File
@@ -1,13 +1,16 @@
import io.spring.gradle.IncludeRepoTask
buildscript {
dependencies {
classpath "io.spring.javaformat:spring-javaformat-gradle-plugin:$springJavaformatVersion"
classpath 'io.spring.nohttp:nohttp-gradle:0.0.10'
classpath "io.freefair.gradle:aspectj-plugin:6.4.3.1"
classpath "io.freefair.gradle:aspectj-plugin:6.2.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "com.netflix.nebula:nebula-project-plugin:8.2.0"
}
repositories {
gradlePluginPortal()
maven { url 'https://repo.spring.io/plugins-snapshot' }
maven { url 'https://plugins.gradle.org/m2/' }
}
}
@@ -15,7 +18,6 @@ apply plugin: 'io.spring.nohttp'
apply plugin: 'locks'
apply plugin: 's101'
apply plugin: 'io.spring.convention.root'
apply plugin: 'io.spring.convention.include-check-remote'
apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'org.springframework.security.update-dependencies'
apply plugin: 'org.springframework.security.update-version'
@@ -102,9 +104,9 @@ updateDependenciesSettings {
dependencyExcludes {
majorVersionBump()
minorVersionBump()
alphaBetaVersions()
releaseCandidatesVersions()
milestoneVersions()
alphaBetaVersions()
snapshotVersions()
addRule { components ->
components.withModule("commons-codec:commons-codec") { selection ->
@@ -200,16 +202,10 @@ nohttp {
}
tasks.register('checkSamples') {
includeCheckRemote {
repository = 'spring-projects/spring-security-samples'
ref = samplesBranch
if (project.hasProperty("samplesInitScript")) {
initScripts = [samplesInitScript]
projectProperties = ["localRepositoryPath": localRepositoryPath, "springSecurityVersion": project.version]
}
}
dependsOn checkRemote
tasks.register('cloneSamples', IncludeRepoTask) {
repository = 'spring-projects/spring-security-samples'
ref = samplesBranch
outputDirectory = project.hasProperty("cloneOutputDirectory") ? project.file("$cloneOutputDirectory") : project.file("build/samples")
}
s101 {
+1 -1
View File
@@ -87,7 +87,7 @@ dependencies {
implementation localGroovy()
implementation 'io.github.gradle-nexus:publish-plugin:1.1.0'
implementation 'io.projectreactor:reactor-core:3.5.0-M1'
implementation 'io.projectreactor:reactor-core:3.4.24'
implementation 'gradle.plugin.org.gretty:gretty:3.0.1'
implementation 'com.apollographql.apollo:apollo-runtime:2.4.5'
implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
@@ -54,7 +54,7 @@ abstract class IncludeRepoTask extends DefaultTask {
* Directory where the project template should be copied.
*/
@OutputDirectory
final File outputDirectory = project.file("$project.buildDir/$name")
File outputDirectory = project.file("$project.buildDir/$name")
@TaskAction
void checkoutAndCopy() {
@@ -1,80 +0,0 @@
/*
* Copyright 2002-2022 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 io.spring.gradle.convention
import io.spring.gradle.IncludeRepoTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.GradleBuild
import org.gradle.api.tasks.TaskProvider
/**
* Adds a set of tasks that make easy to clone a remote repository and perform some task
*
* @author Marcus Da Coregio
*/
class IncludeCheckRemotePlugin implements Plugin<Project> {
@Override
void apply(Project project) {
IncludeCheckRemoteExtension extension = project.extensions.create('includeCheckRemote', IncludeCheckRemoteExtension)
TaskProvider<IncludeRepoTask> includeRepoTask = project.tasks.register('includeRepo', IncludeRepoTask) { IncludeRepoTask it ->
it.repository = extension.repository
it.ref = extension.ref
}
project.tasks.register('checkRemote', GradleBuild) {
it.dependsOn 'includeRepo'
it.dir = includeRepoTask.get().outputDirectory
it.tasks = extension.getTasks()
extension.getInitScripts().forEach {script ->
it.startParameter.addInitScript(new File(script))
}
extension.getProjectProperties().entrySet().forEach { entry ->
it.startParameter.projectProperties.put(entry.getKey(), entry.getValue())
}
}
}
abstract static class IncludeCheckRemoteExtension {
/**
* Git repository to clone
*/
String repository;
/**
* Git ref to checkout
*/
String ref
/**
* Task to run in the repository
*/
List<String> tasks = ['check']
/**
* Init scripts for the build
*/
List<String> initScripts = []
/**
* Map of properties for the build
*/
Map<String, String> projectProperties = [:]
}
}
@@ -59,22 +59,14 @@ public class IntegrationTestPlugin implements Plugin<Project> {
integrationTestRuntime {
extendsFrom integrationTestCompile, testRuntime, testRuntimeOnly
}
integrationTestCompileClasspath {
extendsFrom integrationTestCompile
canBeResolved = true
}
integrationTestRuntimeClasspath {
extendsFrom integrationTestRuntime
canBeResolved = true
}
}
project.sourceSets {
integrationTest {
java.srcDir project.file('src/integration-test/java')
resources.srcDir project.file('src/integration-test/resources')
compileClasspath = project.sourceSets.main.output + project.sourceSets.test.output + project.configurations.integrationTestCompileClasspath
runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntimeClasspath
compileClasspath = project.sourceSets.main.output + project.sourceSets.test.output + project.configurations.integrationTestCompile
runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntime
}
}
@@ -93,7 +85,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
project.idea {
module {
testSourceDirs += project.file('src/integration-test/java')
scopes.TEST.plus += [ project.configurations.integrationTestCompileClasspath ]
scopes.TEST.plus += [ project.configurations.integrationTestCompile ]
}
}
}
@@ -123,7 +115,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
project.plugins.withType(EclipsePlugin) {
project.eclipse.classpath {
plusConfigurations += [ project.configurations.integrationTestCompileClasspath ]
plusConfigurations += [ project.configurations.integrationTestCompile ]
}
}
}
@@ -164,18 +164,14 @@ public class S101Configurer {
String source = "https://structure101.com/binaries/v6";
try (final WebClient webClient = new WebClient()) {
HtmlPage page = webClient.getPage(source);
Matcher matcher = null;
for (HtmlAnchor anchor : page.getAnchors()) {
Matcher candidate = Pattern.compile("(structure101-build-java-all-)(.*).zip").matcher(anchor.getHrefAttribute());
if (candidate.find()) {
matcher = candidate;
Matcher matcher = Pattern.compile("(structure101-build-java-all-)(.*).zip").matcher(anchor.getHrefAttribute());
if (matcher.find()) {
copyZipToFilesystem(source, installationDirectory, matcher.group(1) + matcher.group(2));
return matcher.group(2);
}
}
if (matcher == null) {
return null;
}
copyZipToFilesystem(source, installationDirectory, matcher.group(1) + matcher.group(2));
return matcher.group(2);
return null;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
@@ -1 +0,0 @@
implementation-class=io.spring.gradle.convention.IncludeCheckRemotePlugin
@@ -1,148 +0,0 @@
/*
* Copyright 2002-2022 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 io.spring.gradle.convention;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import io.spring.gradle.IncludeRepoTask;
import org.apache.commons.io.FileUtils;
import org.gradle.api.Project;
import org.gradle.api.tasks.GradleBuild;
import org.gradle.testfixtures.ProjectBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class IncludeCheckRemotePluginTest {
Project rootProject;
@AfterEach
public void cleanup() throws Exception {
if (rootProject != null) {
FileUtils.deleteDirectory(rootProject.getProjectDir());
}
}
@Test
void applyWhenExtensionPropertiesNoTasksThenCreateCheckRemoteTaskWithDefaultTask() {
this.rootProject = ProjectBuilder.builder().build();
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
(includeCheckRemoteExtension) -> {
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
includeCheckRemoteExtension.setProperty("ref", "main");
});
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
assertThat(checkRemote.getTasks()).containsExactly("check");
}
@Test
void applyWhenExtensionPropertiesTasksThenCreateCheckRemoteWithProvidedTasks() {
this.rootProject = ProjectBuilder.builder().build();
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
(includeCheckRemoteExtension) -> {
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
includeCheckRemoteExtension.setProperty("ref", "main");
includeCheckRemoteExtension.setProperty("tasks", Arrays.asList("clean", "build", "test"));
});
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
assertThat(checkRemote.getTasks()).containsExactly("clean", "build", "test");
}
@Test
void applyWhenExtensionPropertiesInitScriptsThenCreateCheckRemoteWithProvidedTasks() {
this.rootProject = ProjectBuilder.builder().build();
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
(includeCheckRemoteExtension) -> {
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
includeCheckRemoteExtension.setProperty("ref", "main");
includeCheckRemoteExtension.setProperty("initScripts", Arrays.asList("spring-security-ci.gradle"));
});
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
assertThat(checkRemote.getStartParameter().getAllInitScripts()).extracting(File::getName).containsExactly("spring-security-ci.gradle");
}
@Test
void applyWhenExtensionPropertiesBuildPropertiesThenCreateCheckRemoteWithProvidedTasks() {
Map<String, String> projectProperties = new HashMap<>();
projectProperties.put("localRepositoryPath", "~/local/repository");
projectProperties.put("anotherProperty", "some_value");
this.rootProject = ProjectBuilder.builder().build();
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
(includeCheckRemoteExtension) -> {
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
includeCheckRemoteExtension.setProperty("ref", "main");
includeCheckRemoteExtension.setProperty("projectProperties", projectProperties);
});
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
assertThat(checkRemote.getStartParameter().getProjectProperties()).containsEntry("localRepositoryPath", "~/local/repository")
.containsEntry("anotherProperty", "some_value");
}
@Test
void applyWhenExtensionPropertiesThenRegisterIncludeRepoTaskWithExtensionProperties() {
this.rootProject = ProjectBuilder.builder().build();
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
(includeCheckRemoteExtension) -> {
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
includeCheckRemoteExtension.setProperty("ref", "main");
});
IncludeRepoTask includeRepo = (IncludeRepoTask) this.rootProject.getTasks().named("includeRepo").get();
assertThat(includeRepo).isNotNull();
assertThat(includeRepo.getRepository().get()).isEqualTo("my-project/my-repository");
assertThat(includeRepo.getRef().get()).isEqualTo("main");
}
@Test
void applyWhenRegisterTasksThenCheckRemoteDirSameAsIncludeRepoOutputDir() {
this.rootProject = ProjectBuilder.builder().build();
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
(includeCheckRemoteExtension) -> {
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
includeCheckRemoteExtension.setProperty("ref", "main");
});
IncludeRepoTask includeRepo = (IncludeRepoTask) this.rootProject.getTasks().named("includeRepo").get();
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
assertThat(checkRemote.getDir()).isEqualTo(includeRepo.getOutputDirectory());
}
@Test
void applyWhenNoExtensionPropertiesThenRegisterTasks() {
this.rootProject = ProjectBuilder.builder().build();
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
IncludeRepoTask includeRepo = (IncludeRepoTask) this.rootProject.getTasks().named("includeRepo").get();
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
assertThat(includeRepo).isNotNull();
assertThat(checkRemote).isNotNull();
}
}
@@ -4,6 +4,7 @@ import java.nio.charset.Charset;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.concurrent.TimeUnit;
import okhttp3.mockwebserver.MockResponse;
@@ -636,7 +637,7 @@ public class GitHubMilestoneApiTests {
" \"state\":\"open\",\n" +
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
" \"due_on\":\"" + Instant.now().toString() + "\",\n" +
" \"due_on\":\"" + LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant().toString() + "\",\n" +
" \"closed_at\":null\n" +
" }\n" +
"]";
@@ -42,8 +42,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
@@ -207,8 +205,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
private AuthenticationFailureHandler proxyFailureHandler = new SimpleUrlAuthenticationFailureHandler();
private SecurityContextRepository securityContextRepository = new NullSecurityContextRepository();
public CasAuthenticationFilter() {
super("/login/cas");
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
@@ -227,7 +223,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authResult);
SecurityContextHolder.setContext(context);
this.securityContextRepository.saveContext(context, request, response);
if (this.eventPublisher != null) {
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
@@ -251,8 +246,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
this.logger.debug("Failed to obtain an artifact (cas ticket)");
password = "";
}
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
password);
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
return this.getAuthenticationManager().authenticate(authRequest);
}
@@ -280,18 +274,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
return result;
}
/**
* Sets the {@link SecurityContextRepository} to save the {@link SecurityContext} on
* authentication success. The default action is not to save the
* {@link SecurityContext}.
* @param securityContextRepository the {@link SecurityContextRepository} to use.
* Cannot be null.
*/
public void setSecurityContextRepository(SecurityContextRepository securityContextRepository) {
Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");
this.securityContextRepository = securityContextRepository;
}
/**
* Sets the {@link AuthenticationFailureHandler} for proxy requests.
* @param proxyFailureHandler
@@ -87,8 +87,8 @@ public class CasAuthenticationProviderTests {
cap.setServiceProperties(makeServiceProperties());
cap.setTicketValidator(new MockTicketValidator(true));
cap.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "ST-123");
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "ST-123");
token.setDetails("details");
Authentication result = cap.authenticate(token);
// Confirm ST-123 was NOT added to the cache
@@ -120,8 +120,8 @@ public class CasAuthenticationProviderTests {
cap.setTicketValidator(new MockTicketValidator(true));
cap.setServiceProperties(makeServiceProperties());
cap.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, "ST-456");
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, "ST-456");
token.setDetails("details");
Authentication result = cap.authenticate(token);
// Confirm ST-456 was added to the cache
@@ -157,8 +157,8 @@ public class CasAuthenticationProviderTests {
cap.setServiceProperties(serviceProperties);
cap.afterPropertiesSet();
String ticket = "ST-456";
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
Authentication result = cap.authenticate(token);
}
@@ -178,8 +178,8 @@ public class CasAuthenticationProviderTests {
cap.setServiceProperties(serviceProperties);
cap.afterPropertiesSet();
String ticket = "ST-456";
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
Authentication result = cap.authenticate(token);
verify(validator).validate(ticket, serviceProperties.getService());
serviceProperties.setAuthenticateAllArtifacts(true);
@@ -211,8 +211,8 @@ public class CasAuthenticationProviderTests {
cap.setTicketValidator(new MockTicketValidator(true));
cap.setServiceProperties(makeServiceProperties());
cap.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "");
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "");
assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> cap.authenticate(token));
}
@@ -314,8 +314,8 @@ public class CasAuthenticationProviderTests {
cap.setTicketValidator(new MockTicketValidator(true));
cap.setServiceProperties(makeServiceProperties());
cap.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.authenticated("some_normal_user", "password", AuthorityUtils.createAuthorityList("ROLE_A"));
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("some_normal_user",
"password", AuthorityUtils.createAuthorityList("ROLE_A"));
assertThat(cap.authenticate(token)).isNull();
}
@@ -121,8 +121,8 @@ public class CasAuthenticationTokenTests {
final Assertion assertion = new AssertionImpl("test");
CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
makeUserDetails(), assertion);
UsernamePasswordAuthenticationToken token2 = UsernamePasswordAuthenticationToken.authenticated("Test",
"Password", this.ROLES);
UsernamePasswordAuthenticationToken token2 = new UsernamePasswordAuthenticationToken("Test", "Password",
this.ROLES);
assertThat(!token1.equals(token2)).isTrue();
}
@@ -21,7 +21,6 @@ import javax.servlet.FilterChain;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@@ -33,15 +32,12 @@ import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.context.SecurityContextRepository;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -186,38 +182,6 @@ public class CasAuthenticationFilterTests {
verify(successHandler).onAuthenticationSuccess(request, response, authentication);
}
@Test
public void testSecurityContextHolder() throws Exception {
SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class);
AuthenticationManager manager = mock(AuthenticationManager.class);
Authentication authentication = new TestingAuthenticationToken("un", "pwd", "ROLE_USER");
given(manager.authenticate(any(Authentication.class))).willReturn(authentication);
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setAuthenticateAllArtifacts(true);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("ticket", "ST-1-123");
request.setServletPath("/authenticate");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = mock(FilterChain.class);
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setServiceProperties(serviceProperties);
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setAuthenticationManager(manager);
filter.setSecurityContextRepository(securityContextRepository);
filter.afterPropertiesSet();
filter.doFilter(request, response, chain);
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull()
.withFailMessage("Authentication should not be null");
verify(chain).doFilter(request, response);
// validate for when the filterProcessUrl matches
filter.setFilterProcessesUrl(request.getServletPath());
SecurityContextHolder.clearContext();
filter.doFilter(request, response, chain);
ArgumentCaptor<SecurityContext> contextArg = ArgumentCaptor.forClass(SecurityContext.class);
verify(securityContextRepository).saveContext(contextArg.capture(), eq(request), eq(response));
assertThat(contextArg.getValue().getAuthentication().getPrincipal()).isEqualTo(authentication.getName());
}
// SEC-1592
@Test
public void testChainNotInvokedForProxyReceptor() throws Exception {
-1
View File
@@ -76,7 +76,6 @@ dependencies {
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 'org.eclipse.persistence:javax.persistence'
testImplementation('org.hibernate:hibernate-entitymanager') {
exclude group: 'javax.activation', module: 'javax.activation-api'
@@ -65,7 +65,7 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
.ldif("classpath:users.xldif") // ldap-server@ldif
.managerDn("uid=admin,ou=system") // ldap-server@manager-dn
.managerPassword("secret") // ldap-server@manager-password
.port(33399) // ldap-server@port
.port(0) // ldap-server@port
.root("dc=springframework,dc=org"); // ldap-server@root
// .url("ldap://localhost:33389/dc-springframework,dc=org") this overrides root and port and is used for external
// @formatter:on
@@ -1,185 +0,0 @@
/*
* Copyright 2002-2022 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.ldap;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.test.web.servlet.MockMvc;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@ExtendWith(SpringTestContextExtension.class)
public class EmbeddedLdapServerContextSourceFactoryBeanITests {
public final SpringTestContext spring = new SpringTestContext(this);
@Autowired
private MockMvc mockMvc;
@Test
public void contextSourceFactoryBeanWhenEmbeddedServerThenAuthenticates() throws Exception {
this.spring.register(FromEmbeddedLdapServerConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
}
@Test
public void contextSourceFactoryBeanWhenPortZeroThenAuthenticates() throws Exception {
this.spring.register(PortZeroConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
}
@Test
public void contextSourceFactoryBeanWhenCustomLdifAndRootThenAuthenticates() throws Exception {
this.spring.register(CustomLdifAndRootConfig.class).autowire();
this.mockMvc.perform(formLogin().user("pg").password("password")).andExpect(authenticated().withUsername("pg"));
}
@Test
public void contextSourceFactoryBeanWhenCustomManagerDnThenAuthenticates() throws Exception {
this.spring.register(CustomManagerDnConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
}
@Test
public void contextSourceFactoryBeanWhenManagerDnAndNoPasswordThenException() {
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
.isThrownBy(() -> this.spring.register(CustomManagerDnNoPasswordConfig.class).autowire())
.withRootCauseInstanceOf(IllegalStateException.class)
.withMessageContaining("managerPassword is required if managerDn is supplied");
}
@EnableWebSecurity
static class FromEmbeddedLdapServerConfig {
@Bean
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
return EmbeddedLdapServerContextSourceFactoryBean.fromEmbeddedLdapServer();
}
@Bean
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class PortZeroConfig {
@Bean
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
.fromEmbeddedLdapServer();
factoryBean.setPort(0);
return factoryBean;
}
@Bean
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class CustomLdifAndRootConfig {
@Bean
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
.fromEmbeddedLdapServer();
factoryBean.setLdif("classpath*:test-server2.xldif");
factoryBean.setRoot("dc=monkeymachine,dc=co,dc=uk");
return factoryBean;
}
@Bean
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=gorillas");
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class CustomManagerDnConfig {
@Bean
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
.fromEmbeddedLdapServer();
factoryBean.setManagerDn("uid=admin,ou=system");
factoryBean.setManagerPassword("secret");
return factoryBean;
}
@Bean
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
LdapPasswordComparisonAuthenticationManagerFactory factory = new LdapPasswordComparisonAuthenticationManagerFactory(
contextSource, NoOpPasswordEncoder.getInstance());
factory.setUserDnPatterns("uid={0},ou=people");
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class CustomManagerDnNoPasswordConfig {
@Bean
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
.fromEmbeddedLdapServer();
factoryBean.setManagerDn("uid=admin,ou=system");
return factoryBean;
}
@Bean
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
LdapPasswordComparisonAuthenticationManagerFactory factory = new LdapPasswordComparisonAuthenticationManagerFactory(
contextSource, NoOpPasswordEncoder.getInstance());
factory.setUserDnPatterns("uid={0},ou=people");
return factory.createAuthenticationManager();
}
}
}
@@ -1,241 +0,0 @@
/*
* Copyright 2002-2022 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.ldap;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
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.userdetails.DefaultLdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.Mockito.mock;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@ExtendWith(SpringTestContextExtension.class)
public class LdapBindAuthenticationManagerFactoryITests {
public final SpringTestContext spring = new SpringTestContext(this);
@Autowired
private MockMvc mockMvc;
@Test
public void authenticationManagerFactoryWhenFromContextSourceThenAuthenticates() throws Exception {
this.spring.register(FromContextSourceConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
}
@Test
public void ldapAuthenticationProviderCustomLdapAuthoritiesPopulator() throws Exception {
CustomAuthoritiesPopulatorConfig.LAP = new DefaultLdapAuthoritiesPopulator(mock(LdapContextSource.class),
null) {
@Override
protected Set<GrantedAuthority> getAdditionalRoles(DirContextOperations user, String username) {
return new HashSet<>(AuthorityUtils.createAuthorityList("ROLE_EXTRA"));
}
};
this.spring.register(CustomAuthoritiesPopulatorConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(
authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA"))));
}
@Test
public void authenticationManagerFactoryWhenCustomAuthoritiesMapperThenUsed() throws Exception {
CustomAuthoritiesMapperConfig.AUTHORITIES_MAPPER = ((authorities) -> AuthorityUtils
.createAuthorityList("ROLE_CUSTOM"));
this.spring.register(CustomAuthoritiesMapperConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(
authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_CUSTOM"))));
}
@Test
public void authenticationManagerFactoryWhenCustomUserDetailsContextMapperThenUsed() throws Exception {
CustomUserDetailsContextMapperConfig.CONTEXT_MAPPER = new UserDetailsContextMapper() {
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
Collection<? extends GrantedAuthority> authorities) {
return User.withUsername("other").password("password").roles("USER").build();
}
@Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
}
};
this.spring.register(CustomUserDetailsContextMapperConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("other"));
}
@Test
public void authenticationManagerFactoryWhenCustomUserDnPatternsThenUsed() throws Exception {
this.spring.register(CustomUserDnPatternsConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
}
@Test
public void authenticationManagerFactoryWhenCustomUserSearchThenUsed() throws Exception {
this.spring.register(CustomUserSearchConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
}
@EnableWebSecurity
static class FromContextSourceConfig extends BaseLdapServerConfig {
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class CustomAuthoritiesMapperConfig extends BaseLdapServerConfig {
static GrantedAuthoritiesMapper AUTHORITIES_MAPPER;
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
factory.setAuthoritiesMapper(AUTHORITIES_MAPPER);
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class CustomAuthoritiesPopulatorConfig extends BaseLdapServerConfig {
static LdapAuthoritiesPopulator LAP;
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
factory.setLdapAuthoritiesPopulator(LAP);
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class CustomUserDetailsContextMapperConfig extends BaseLdapServerConfig {
static UserDetailsContextMapper CONTEXT_MAPPER;
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
factory.setUserDetailsContextMapper(CONTEXT_MAPPER);
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class CustomUserDnPatternsConfig extends BaseLdapServerConfig {
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class CustomUserSearchConfig extends BaseLdapServerConfig {
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserSearchFilter("uid={0}");
factory.setUserSearchBase("ou=people");
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
abstract static class BaseLdapServerConfig implements DisposableBean {
private ApacheDSContainer container;
@Bean
ApacheDSContainer ldapServer() throws Exception {
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
this.container.setPort(0);
return this.container;
}
@Bean
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
int port = container.getLocalPort();
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
}
@Override
public void destroy() {
this.container.stop();
}
}
}
@@ -1,114 +0,0 @@
/*
* Copyright 2002-2022 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.ldap;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
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.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@ExtendWith(SpringTestContextExtension.class)
public class LdapPasswordComparisonAuthenticationManagerFactoryITests {
public final SpringTestContext spring = new SpringTestContext(this);
@Autowired
private MockMvc mockMvc;
@Test
public void authenticationManagerFactoryWhenCustomPasswordEncoderThenUsed() throws Exception {
this.spring.register(CustomPasswordEncoderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bcrypt").password("password"))
.andExpect(authenticated().withUsername("bcrypt"));
}
@Test
public void authenticationManagerFactoryWhenCustomPasswordAttributeThenUsed() throws Exception {
this.spring.register(CustomPasswordAttributeConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bob")).andExpect(authenticated().withUsername("bob"));
}
@EnableWebSecurity
static class CustomPasswordEncoderConfig extends BaseLdapServerConfig {
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapPasswordComparisonAuthenticationManagerFactory factory = new LdapPasswordComparisonAuthenticationManagerFactory(
contextSource, new BCryptPasswordEncoder());
factory.setUserDnPatterns("uid={0},ou=people");
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
static class CustomPasswordAttributeConfig extends BaseLdapServerConfig {
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapPasswordComparisonAuthenticationManagerFactory factory = new LdapPasswordComparisonAuthenticationManagerFactory(
contextSource, NoOpPasswordEncoder.getInstance());
factory.setPasswordAttribute("uid");
factory.setUserDnPatterns("uid={0},ou=people");
return factory.createAuthenticationManager();
}
}
@EnableWebSecurity
abstract static class BaseLdapServerConfig implements DisposableBean {
private ApacheDSContainer container;
@Bean
ApacheDSContainer ldapServer() throws Exception {
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
this.container.setPort(0);
return this.container;
}
@Bean
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
int port = container.getLocalPort();
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
}
@Override
public void destroy() {
this.container.stop();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2020 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.
@@ -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(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
UserDetails ben = (UserDetails) auth.getPrincipal();
assertThat(ben.getAuthorities()).hasSize(3);
}
@@ -89,7 +89,7 @@ public class LdapProviderBeanDefinitionParserTests {
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
assertThat(auth).isNotNull();
}
@@ -104,8 +104,7 @@ public class LdapProviderBeanDefinitionParserTests {
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "ben"));
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
assertThat(auth).isNotNull();
}
@@ -122,7 +121,7 @@ public class LdapProviderBeanDefinitionParserTests {
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("bcrypt", "password"));
.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", "password"));
assertThat(auth).isNotNull();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -138,10 +138,4 @@ public abstract class Elements {
public static final String PASSWORD_MANAGEMENT = "password-management";
public static final String RELYING_PARTY_REGISTRATIONS = "relying-party-registrations";
public static final String SAML2_LOGIN = "saml2-login";
public static final String SAML2_LOGOUT = "saml2-logout";
}
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2022 the original author or authors.
* Copyright 2009-2020 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.
@@ -47,7 +47,6 @@ import org.springframework.security.config.method.InterceptMethodsBeanDefinition
import org.springframework.security.config.method.MethodSecurityBeanDefinitionParser;
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
import org.springframework.security.config.oauth2.client.ClientRegistrationsBeanDefinitionParser;
import org.springframework.security.config.saml2.RelyingPartyRegistrationsBeanDefinitionParser;
import org.springframework.security.config.websocket.WebSocketMessageBrokerSecurityBeanDefinitionParser;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.ClassUtils;
@@ -95,7 +94,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
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 5.7. Please update your schema declarations to the 5.7 schema.", element);
+ "with Spring Security 5.6. Please update your schema declarations to the 5.6 schema.", element);
}
String name = pc.getDelegate().getLocalName(element);
BeanDefinitionParser parser = this.parsers.get(name);
@@ -191,7 +190,6 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
this.parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
this.filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
this.parsers.put(Elements.CLIENT_REGISTRATIONS, new ClientRegistrationsBeanDefinitionParser());
this.parsers.put(Elements.RELYING_PARTY_REGISTRATIONS, new RelyingPartyRegistrationsBeanDefinitionParser());
}
private void loadWebSocketParsers() {
@@ -217,7 +215,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-5\\.7.*.xsd.*")
return schemaLocation.matches("(?m).*spring-security-5\\.6.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@@ -39,6 +39,7 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.log.LogMessage;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
@@ -79,8 +80,7 @@ public class AuthenticationConfiguration {
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
ApplicationContext context) {
LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
AuthenticationEventPublisher authenticationEventPublisher = getBeanOrNull(context,
AuthenticationEventPublisher.class);
AuthenticationEventPublisher authenticationEventPublisher = getAuthenticationEventPublisher(context);
DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(
objectPostProcessor, defaultPasswordEncoder);
if (authenticationEventPublisher != null) {
@@ -142,6 +142,13 @@ public class AuthenticationConfiguration {
this.objectPostProcessor = objectPostProcessor;
}
private AuthenticationEventPublisher getAuthenticationEventPublisher(ApplicationContext context) {
if (context.getBeanNamesForType(AuthenticationEventPublisher.class).length > 0) {
return context.getBean(AuthenticationEventPublisher.class);
}
return this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
}
@SuppressWarnings("unchecked")
private <T> T lazyBean(Class<T> interfaceName) {
LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2013 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.
@@ -39,19 +39,10 @@ import org.springframework.security.config.annotation.web.servlet.configuration.
* &#064;EnableGlobalAuthentication
* public class MyGlobalAuthenticationConfiguration {
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;user&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* UserDetails admin = User.withDefaultPasswordEncoder()
* .username(&quot;admin&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;ADMIN&quot;, &quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user, admin);
* &#064;Autowired
* public void configureGlobal(AuthenticationManagerBuilder auth) {
* auth.inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;)
* .and().withUser(&quot;admin&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;, &quot;ADMIN&quot;);
* }
* }
* </pre>
@@ -63,24 +54,15 @@ import org.springframework.security.config.annotation.web.servlet.configuration.
* <pre class="code">
* &#064;Configuration
* &#064;EnableWebSecurity
* public class MyWebSecurityConfiguration {
* public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;user&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* UserDetails admin = User.withDefaultPasswordEncoder()
* .username(&quot;admin&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;ADMIN&quot;, &quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user, admin);
* &#064;Autowired
* public void configureGlobal(AuthenticationManagerBuilder auth) {
* auth.inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;)
* .and().withUser(&quot;admin&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;, &quot;ADMIN&quot;);
* }
*
* // Possibly more bean methods ...
* // Possibly overridden methods ...
* }
* </pre>
*
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -17,16 +17,16 @@
package org.springframework.security.config.annotation.method.configuration;
import org.springframework.aop.Advisor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager;
@@ -45,64 +45,59 @@ import org.springframework.security.config.core.GrantedAuthorityDefaults;
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
final class PrePostMethodSecurityConfiguration {
final class PrePostMethodSecurityConfiguration implements ApplicationContextAware {
private final PreFilterAuthorizationMethodInterceptor preFilterAuthorizationMethodInterceptor = new PreFilterAuthorizationMethodInterceptor();
private final AuthorizationManagerBeforeMethodInterceptor preAuthorizeAuthorizationMethodInterceptor;
private final PreAuthorizeAuthorizationManager preAuthorizeAuthorizationManager = new PreAuthorizeAuthorizationManager();
private final AuthorizationManagerAfterMethodInterceptor postAuthorizeAuthorizaitonMethodInterceptor;
private final PostAuthorizeAuthorizationManager postAuthorizeAuthorizationManager = new PostAuthorizeAuthorizationManager();
private final PostFilterAuthorizationMethodInterceptor postFilterAuthorizationMethodInterceptor = new PostFilterAuthorizationMethodInterceptor();
private final DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
@Autowired
PrePostMethodSecurityConfiguration(ApplicationContext context) {
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
this.preAuthorizeAuthorizationMethodInterceptor = AuthorizationManagerBeforeMethodInterceptor
.preAuthorize(this.preAuthorizeAuthorizationManager);
this.postAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
this.postAuthorizeAuthorizaitonMethodInterceptor = AuthorizationManagerAfterMethodInterceptor
.postAuthorize(this.postAuthorizeAuthorizationManager);
this.preFilterAuthorizationMethodInterceptor.setExpressionHandler(this.expressionHandler);
this.postFilterAuthorizationMethodInterceptor.setExpressionHandler(this.expressionHandler);
this.expressionHandler.setApplicationContext(context);
AuthorizationEventPublisher publisher = new SpringAuthorizationEventPublisher(context);
this.preAuthorizeAuthorizationMethodInterceptor.setAuthorizationEventPublisher(publisher);
this.postAuthorizeAuthorizaitonMethodInterceptor.setAuthorizationEventPublisher(publisher);
}
private boolean customMethodSecurityExpressionHandler = false;
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor preFilterAuthorizationMethodInterceptor() {
if (!this.customMethodSecurityExpressionHandler) {
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
}
return this.preFilterAuthorizationMethodInterceptor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor preAuthorizeAuthorizationMethodInterceptor() {
return this.preAuthorizeAuthorizationMethodInterceptor;
if (!this.customMethodSecurityExpressionHandler) {
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
}
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(this.preAuthorizeAuthorizationManager);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor postAuthorizeAuthorizationMethodInterceptor() {
return this.postAuthorizeAuthorizaitonMethodInterceptor;
if (!this.customMethodSecurityExpressionHandler) {
this.postAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
}
return AuthorizationManagerAfterMethodInterceptor.postAuthorize(this.postAuthorizeAuthorizationManager);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor postFilterAuthorizationMethodInterceptor() {
if (!this.customMethodSecurityExpressionHandler) {
this.postFilterAuthorizationMethodInterceptor.setExpressionHandler(this.expressionHandler);
}
return this.postFilterAuthorizationMethodInterceptor;
}
@Autowired(required = false)
void setMethodSecurityExpressionHandler(MethodSecurityExpressionHandler methodSecurityExpressionHandler) {
this.customMethodSecurityExpressionHandler = true;
this.preFilterAuthorizationMethodInterceptor.setExpressionHandler(methodSecurityExpressionHandler);
this.preAuthorizeAuthorizationManager.setExpressionHandler(methodSecurityExpressionHandler);
this.postAuthorizeAuthorizationManager.setExpressionHandler(methodSecurityExpressionHandler);
@@ -114,10 +109,9 @@ final class PrePostMethodSecurityConfiguration {
this.expressionHandler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
@Autowired(required = false)
void setAuthorizationEventPublisher(AuthorizationEventPublisher eventPublisher) {
this.preAuthorizeAuthorizationMethodInterceptor.setAuthorizationEventPublisher(eventPublisher);
this.postAuthorizeAuthorizaitonMethodInterceptor.setAuthorizationEventPublisher(eventPublisher);
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.expressionHandler.setApplicationContext(context);
}
}
@@ -42,8 +42,6 @@ import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
import org.springframework.security.web.session.SessionManagementFilter;
/**
@@ -126,8 +124,6 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
* The ordering of the Filters is:
*
* <ul>
* <li>{@link ForceEagerSessionCreationFilter}</li>
* <li>{@link DisableEncodeUrlFilter}</li>
* <li>{@link ChannelProcessingFilter}</li>
* <li>{@link SecurityContextPersistenceFilter}</li>
* <li>{@link LogoutFilter}</li>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2020 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.
@@ -23,16 +23,19 @@ import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.SecurityFilterChain;
/**
* Allows customization to the {@link WebSecurity}. In most instances users will use
* {@link EnableWebSecurity} and create a {@link Configuration} that exposes a
* {@link SecurityFilterChain} bean. This will automatically be applied to the
* {@link WebSecurity} by the {@link EnableWebSecurity} annotation.
* {@link EnableWebSecurity} and either create a {@link Configuration} that extends
* {@link WebSecurityConfigurerAdapter} or expose a {@link SecurityFilterChain} bean. Both
* will automatically be applied to the {@link WebSecurity} by the
* {@link EnableWebSecurity} annotation.
*
* @author Rob Winch
* @since 3.2
* @see WebSecurityConfigurerAdapter
* @see SecurityFilterChain
*/
public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends SecurityConfigurer<Filter, T> {
@@ -37,7 +37,6 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera
import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
import org.springframework.security.web.context.SecurityContextHolderFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.security.web.csrf.CsrfFilter;
@@ -46,8 +45,6 @@ import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.web.filter.CorsFilter;
@@ -70,12 +67,9 @@ final class FilterOrderRegistration {
FilterOrderRegistration() {
Step order = new Step(INITIAL_ORDER, ORDER_STEP);
put(DisableEncodeUrlFilter.class, order.next());
put(ForceEagerSessionCreationFilter.class, order.next());
put(ChannelProcessingFilter.class, order.next());
order.next(); // gh-8105
put(WebAsyncManagerIntegrationFilter.class, order.next());
put(SecurityContextHolderFilter.class, order.next());
put(SecurityContextPersistenceFilter.class, order.next());
put(HeaderWriterFilter.class, order.next());
put(CorsFilter.class, order.next());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -42,6 +42,7 @@ import org.springframework.security.config.annotation.web.AbstractRequestMatcher
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.DefaultSecurityFilterChain;
@@ -76,7 +77,8 @@ import org.springframework.web.filter.DelegatingFilterProxy;
*
* <p>
* Customizations to the {@link WebSecurity} can be made by creating a
* {@link WebSecurityConfigurer} or exposing a {@link WebSecurityCustomizer} bean.
* {@link WebSecurityConfigurer}, overriding {@link WebSecurityConfigurerAdapter} or
* exposing a {@link WebSecurityCustomizer} bean.
* </p>
*
* @author Rob Winch
@@ -198,7 +200,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
*
* <p>
* Typically this method is invoked automatically within the framework from
* {@link WebSecurityConfiguration#springSecurityFilterChain()}
* {@link WebSecurityConfigurerAdapter#init(WebSecurity)}
* </p>
* @param securityFilterChainBuilder the builder to use to create the
* {@link SecurityFilterChain} instances
@@ -256,7 +258,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
/**
* Sets the {@link FilterSecurityInterceptor}. This is typically invoked by
* {@link WebSecurityConfiguration#springSecurityFilterChain()}.
* {@link WebSecurityConfigurerAdapter}.
* @param securityInterceptor the {@link FilterSecurityInterceptor} to use
* @return the {@link WebSecurity} for further customizations
* @deprecated Use {@link #privilegeEvaluator(WebInvocationPrivilegeEvaluator)}
@@ -278,24 +280,12 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
return this;
}
/**
* Sets the handler to handle
* {@link org.springframework.security.web.firewall.RequestRejectedException}
* @param requestRejectedHandler
* @return the {@link WebSecurity} for further customizations
* @since 5.7
*/
public WebSecurity requestRejectedHandler(RequestRejectedHandler requestRejectedHandler) {
Assert.notNull(requestRejectedHandler, "requestRejectedHandler cannot be null");
this.requestRejectedHandler = requestRejectedHandler;
return this;
}
@Override
protected Filter performBuild() throws Exception {
Assert.state(!this.securityFilterChainBuilders.isEmpty(),
() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
+ "Typically this is done by exposing a SecurityFilterChain bean. "
+ "Typically this is done by exposing a SecurityFilterChain bean "
+ "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+ "More advanced users can invoke " + WebSecurity.class.getSimpleName()
+ ".addSecurityFilterChainBuilder directly");
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2020 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.
@@ -26,56 +26,48 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.web.SecurityFilterChain;
/**
* Add this annotation to an {@code @Configuration} class to have the Spring Security
* configuration defined in any {@link WebSecurityConfigurer} or more likely by exposing a
* {@link SecurityFilterChain} bean:
* configuration defined in any {@link WebSecurityConfigurer} or more likely by extending
* the {@link WebSecurityConfigurerAdapter} base class and overriding individual methods:
*
* <pre class="code">
* &#064;Configuration
* &#064;EnableWebSecurity
* public class MyWebSecurityConfiguration {
* public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
*
* &#064;Bean
* public WebSecurityCustomizer webSecurityCustomizer() {
* return (web) -> web.ignoring()
* &#064;Override
* public void configure(WebSecurity web) throws Exception {
* web.ignoring()
* // Spring Security should completely ignore URLs starting with /resources/
* .antMatchers(&quot;/resources/**&quot;);
* }
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http.authorizeRequests().antMatchers(&quot;/public/**&quot;).permitAll().anyRequest()
* .hasRole(&quot;USER&quot;).and()
* // Possibly more configuration ...
* .formLogin() // enable form based log in
* // set permitAll for all URLs associated with Form Login
* .permitAll();
* return http.build();
* }
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;user&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* UserDetails admin = User.withDefaultPasswordEncoder()
* .username(&quot;admin&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;ADMIN&quot;, &quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user, admin);
* &#064;Override
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
* auth
* // enable in memory based authentication with a user named &quot;user&quot; and &quot;admin&quot;
* .inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;)
* .and().withUser(&quot;admin&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;, &quot;ADMIN&quot;);
* }
*
* // Possibly more bean methods ...
* // Possibly more overridden methods ...
* }
* </pre>
*
* @see WebSecurityConfigurer
* @see WebSecurityConfigurerAdapter
*
* @author Rob Winch
* @since 3.2
@@ -17,7 +17,6 @@
package org.springframework.security.config.annotation.web.configuration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
@@ -25,13 +24,13 @@ 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.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.annotation.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.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.web.context.request.async.WebAsyncManagerIntegrationFilter;
@@ -85,6 +84,7 @@ class HttpSecurityConfiguration {
AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);
authenticationBuilder.parentAuthenticationManager(authenticationManager());
authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
// @formatter:off
http
@@ -100,7 +100,6 @@ class HttpSecurityConfiguration {
.apply(new DefaultLoginPageConfigurer<>());
http.logout(withDefaults());
// @formatter:on
applyDefaultConfigurers(http);
return http;
}
@@ -109,13 +108,11 @@ class HttpSecurityConfiguration {
: this.authenticationConfiguration.getAuthenticationManager();
}
private void applyDefaultConfigurers(HttpSecurity http) throws Exception {
ClassLoader classLoader = this.context.getClassLoader();
List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
.loadFactories(AbstractHttpConfigurer.class, classLoader);
for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
http.apply(configurer);
private AuthenticationEventPublisher getAuthenticationEventPublisher() {
if (this.context.getBeanNamesForType(AuthenticationEventPublisher.class).length > 0) {
return this.context.getBean(AuthenticationEventPublisher.class);
}
return this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
}
private Map<Class<?>, Object> createSharedObjects() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2020 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.
@@ -16,14 +16,10 @@
package org.springframework.security.config.annotation.web.configuration;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -71,22 +67,17 @@ class SecurityReactorContextConfiguration {
private static final String SECURITY_REACTOR_CONTEXT_OPERATOR_KEY = "org.springframework.security.SECURITY_REACTOR_CONTEXT_OPERATOR";
private static final Map<Object, Supplier<Object>> CONTEXT_ATTRIBUTE_VALUE_LOADERS = new HashMap<>();
static {
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletRequest.class,
SecurityReactorContextSubscriberRegistrar::getRequest);
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletResponse.class,
SecurityReactorContextSubscriberRegistrar::getResponse);
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(Authentication.class,
SecurityReactorContextSubscriberRegistrar::getAuthentication);
}
@Override
public void afterPropertiesSet() throws Exception {
Function<? super Publisher<Object>, ? extends Publisher<Object>> lifter = Operators
.liftPublisher((pub, sub) -> createSubscriberIfNecessary(sub));
Hooks.onLastOperator(SECURITY_REACTOR_CONTEXT_OPERATOR_KEY, lifter::apply);
Hooks.onLastOperator(SECURITY_REACTOR_CONTEXT_OPERATOR_KEY, (pub) -> {
if (!contextAttributesAvailable()) {
// No need to decorate so return original Publisher
return pub;
}
return lifter.apply(pub);
});
}
@Override
@@ -102,30 +93,36 @@ class SecurityReactorContextConfiguration {
return new SecurityReactorContextSubscriber<>(delegate, getContextAttributes());
}
private static boolean contextAttributesAvailable() {
return SecurityContextHolder.getContext().getAuthentication() != null
|| RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes;
}
private static Map<Object, Object> getContextAttributes() {
return new LoadingMap<>(CONTEXT_ATTRIBUTE_VALUE_LOADERS);
}
private static HttpServletRequest getRequest() {
HttpServletRequest servletRequest = null;
HttpServletResponse servletResponse = null;
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
return servletRequestAttributes.getRequest();
servletRequest = servletRequestAttributes.getRequest();
servletResponse = servletRequestAttributes.getResponse(); // possible null
}
return null;
}
private static HttpServletResponse getResponse() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
return servletRequestAttributes.getResponse(); // possible null
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null && servletRequest == null) {
return Collections.emptyMap();
}
Map<Object, Object> contextAttributes = new HashMap<>();
if (servletRequest != null) {
contextAttributes.put(HttpServletRequest.class, servletRequest);
}
if (servletResponse != null) {
contextAttributes.put(HttpServletResponse.class, servletResponse);
}
if (authentication != null) {
contextAttributes.put(Authentication.class, authentication);
}
return null;
}
private static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
return contextAttributes;
}
}
@@ -178,112 +175,4 @@ class SecurityReactorContextConfiguration {
}
/**
* A map that computes each value when {@link #get} is invoked
*/
static class LoadingMap<K, V> implements Map<K, V> {
private final Map<K, V> loaded = new ConcurrentHashMap<>();
private final Map<K, Supplier<V>> loaders;
LoadingMap(Map<K, Supplier<V>> loaders) {
this.loaders = Collections.unmodifiableMap(new HashMap<>(loaders));
}
@Override
public int size() {
return this.loaders.size();
}
@Override
public boolean isEmpty() {
return this.loaders.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return this.loaders.containsKey(key);
}
@Override
public Set<K> keySet() {
return this.loaders.keySet();
}
@Override
public V get(Object key) {
if (!this.loaders.containsKey(key)) {
throw new IllegalArgumentException(
"This map only supports the following keys: " + this.loaders.keySet());
}
return this.loaded.computeIfAbsent((K) key, (k) -> this.loaders.get(k).get());
}
@Override
public V put(K key, V value) {
if (!this.loaders.containsKey(key)) {
throw new IllegalArgumentException(
"This map only supports the following keys: " + this.loaders.keySet());
}
return this.loaded.put(key, value);
}
@Override
public V remove(Object key) {
if (!this.loaders.containsKey(key)) {
throw new IllegalArgumentException(
"This map only supports the following keys: " + this.loaders.keySet());
}
return this.loaded.remove(key);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public void clear() {
this.loaded.clear();
}
@Override
public boolean containsValue(Object value) {
return this.loaded.containsValue(value);
}
@Override
public Collection<V> values() {
return this.loaded.values();
}
@Override
public Set<Entry<K, V>> entrySet() {
return this.loaded.entrySet();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LoadingMap<?, ?> that = (LoadingMap<?, ?>) o;
return this.loaded.equals(that.loaded);
}
@Override
public int hashCode() {
return this.loaded.hashCode();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2020 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.
@@ -24,6 +24,7 @@ import javax.servlet.Filter;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
@@ -54,9 +55,10 @@ import org.springframework.util.Assert;
/**
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
* based security for Spring Security. It then exports the necessary beans. Customizations
* can be made to {@link WebSecurity} by implementing {@link WebSecurityConfigurer} and
* exposing it as a {@link Configuration} or exposing a {@link WebSecurityCustomizer}
* bean. This configuration is imported when using {@link EnableWebSecurity}.
* can be made to {@link WebSecurity} by extending {@link WebSecurityConfigurerAdapter}
* and exposing it as a {@link Configuration} or implementing
* {@link WebSecurityConfigurer} and exposing it as a {@link Configuration}. This
* configuration is imported when using {@link EnableWebSecurity}.
*
* @author Rob Winch
* @author Keesun Baik
@@ -141,20 +143,19 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
* instances used to create the web configuration.
* @param objectPostProcessor the {@link ObjectPostProcessor} used to create a
* {@link WebSecurity} instance
* @param beanFactory the bean factory to use to retrieve the relevant
* @param webSecurityConfigurers the
* {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to
* create the web configuration
* @throws Exception
*/
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
ConfigurableListableBeanFactory beanFactory) throws Exception {
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if (this.debugEnabled != null) {
this.webSecurity.debug(this.debugEnabled);
}
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new AutowiredWebSecurityConfigurersIgnoreParents(
beanFactory).getWebSecurityConfigurers();
webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null;
@@ -188,6 +189,12 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
return new RsaKeyConversionServicePostProcessor();
}
@Bean
public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
ConfigurableListableBeanFactory beanFactory) {
return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
}
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
Map<String, Object> enableWebSecurityAttrMap = importMetadata
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -89,12 +89,8 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
*
* @author Rob Winch
* @see EnableWebSecurity
* @deprecated Use a {@link org.springframework.security.web.SecurityFilterChain} Bean to
* configure {@link HttpSecurity} or a {@link WebSecurityCustomizer} Bean to configure
* {@link WebSecurity}
*/
@Order(100)
@Deprecated
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
private final Log logger = LogFactory.getLog(WebSecurityConfigurerAdapter.class);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.PortMapper;
@@ -38,7 +38,6 @@ import org.springframework.security.web.authentication.SavedRequestAwareAuthenti
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
@@ -147,11 +146,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
return getSelf();
}
public T securityContextRepository(SecurityContextRepository securityContextRepository) {
this.authFilter.setSecurityContextRepository(securityContextRepository);
return getSelf();
}
/**
* Create the {@link RequestMatcher} given a loginProcessingUrl
* @param loginProcessingUrl creates the {@link RequestMatcher} based upon the
@@ -293,12 +287,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
if (rememberMeServices != null) {
this.authFilter.setRememberMeServices(rememberMeServices);
}
SecurityContextConfigurer securityContextConfigurer = http.getConfigurer(SecurityContextConfigurer.class);
if (securityContextConfigurer != null && securityContextConfigurer.isRequireExplicitSave()) {
SecurityContextRepository securityContextRepository = securityContextConfigurer
.getSecurityContextRepository();
this.authFilter.setSecurityContextRepository(securityContextRepository);
}
F filter = postProcess(this.authFilter);
http.addFilter(filter);
}
@@ -306,14 +294,14 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
/**
* <p>
* Specifies the URL to send users to if login is required. If used with
* {@link EnableWebSecurity} a default login page will be generated when this
* attribute is not specified.
* {@link WebSecurityConfigurerAdapter} a default login page will be generated when
* this attribute is not specified.
* </p>
*
* <p>
* If a URL is specified or this is not being used in conjunction with
* {@link EnableWebSecurity}, users are required to process the specified URL to
* generate a login page.
* {@link WebSecurityConfigurerAdapter}, users are required to process the specified
* URL to generate a login page.
* </p>
*/
protected T loginPage(String loginPage) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2020 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.
@@ -25,9 +25,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthorityAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
@@ -36,7 +34,6 @@ import org.springframework.security.web.access.intercept.RequestAuthorizationCon
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
import org.springframework.util.Assert;
/**
@@ -49,25 +46,14 @@ import org.springframework.util.Assert;
public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<AuthorizeHttpRequestsConfigurer<H>, H> {
static final AuthorizationManager<RequestAuthorizationContext> permitAllAuthorizationManager = (a,
o) -> new AuthorizationDecision(true);
private final AuthorizationManagerRequestMatcherRegistry registry;
private final AuthorizationEventPublisher publisher;
/**
* Creates an instance.
* @param context the {@link ApplicationContext} to use
*/
public AuthorizeHttpRequestsConfigurer(ApplicationContext context) {
this.registry = new AuthorizationManagerRequestMatcherRegistry(context);
if (context.getBeanNamesForType(AuthorizationEventPublisher.class).length > 0) {
this.publisher = context.getBean(AuthorizationEventPublisher.class);
}
else {
this.publisher = new SpringAuthorizationEventPublisher(context);
}
}
/**
@@ -84,8 +70,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
public void configure(H http) {
AuthorizationManager<HttpServletRequest> authorizationManager = this.registry.createAuthorizationManager();
AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
authorizationFilter.setAuthorizationEventPublisher(this.publisher);
authorizationFilter.setShouldFilterAllDispatcherTypes(this.registry.shouldFilterAllDispatcherTypes);
http.addFilter(postProcess(authorizationFilter));
}
@@ -97,12 +81,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
return this.registry;
}
AuthorizationManagerRequestMatcherRegistry addFirst(RequestMatcher matcher,
AuthorizationManager<RequestAuthorizationContext> manager) {
this.registry.addFirst(matcher, manager);
return this.registry;
}
/**
* Registry for mapping a {@link RequestMatcher} to an {@link AuthorizationManager}.
*
@@ -118,8 +96,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
private int mappingCount;
private boolean shouldFilterAllDispatcherTypes = false;
private AuthorizationManagerRequestMatcherRegistry(ApplicationContext context) {
setApplicationContext(context);
}
@@ -130,12 +106,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
this.mappingCount++;
}
private void addFirst(RequestMatcher matcher, AuthorizationManager<RequestAuthorizationContext> manager) {
this.unmappedMatchers = null;
this.managerBuilder.mappings((m) -> m.add(0, new RequestMatcherEntry<>(matcher, manager)));
this.mappingCount++;
}
private AuthorizationManager<HttpServletRequest> createAuthorizationManager() {
Assert.state(this.unmappedMatchers == null,
() -> "An incomplete mapping was found for " + this.unmappedMatchers
@@ -173,19 +143,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
return this;
}
/**
* Sets whether all dispatcher types should be filtered.
* @param shouldFilter should filter all dispatcher types. Default is
* {@code false}
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
* customizations
* @since 5.7
*/
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.
@@ -252,7 +209,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry permitAll() {
return access(permitAllAuthorizationManager);
return access((a, o) -> new AuthorizationDecision(true));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2013 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.
@@ -30,9 +30,7 @@ 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;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.access.channel.ChannelProcessor;
@@ -77,7 +75,6 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
*
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
* @author Rob Winch
* @author Onur Kagan Ozcan
* @since 3.2
*/
public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
@@ -89,8 +86,6 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
private List<ChannelProcessor> channelProcessors;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private final ChannelRequestMatcherRegistry REGISTRY;
/**
@@ -128,11 +123,9 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
if (portMapper != null) {
RetryWithHttpEntryPoint httpEntryPoint = new RetryWithHttpEntryPoint();
httpEntryPoint.setPortMapper(portMapper);
httpEntryPoint.setRedirectStrategy(this.redirectStrategy);
insecureChannelProcessor.setEntryPoint(httpEntryPoint);
RetryWithHttpsEntryPoint httpsEntryPoint = new RetryWithHttpsEntryPoint();
httpsEntryPoint.setPortMapper(portMapper);
httpsEntryPoint.setRedirectStrategy(this.redirectStrategy);
secureChannelProcessor.setEntryPoint(httpsEntryPoint);
}
insecureChannelProcessor = postProcess(insecureChannelProcessor);
@@ -192,17 +185,6 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
return this;
}
/**
* Sets the {@link RedirectStrategy} instances to use in
* {@link RetryWithHttpEntryPoint} and {@link RetryWithHttpsEntryPoint}
* @param redirectStrategy
* @return the {@link ChannelSecurityConfigurer} for further customizations
*/
public ChannelRequestMatcherRegistry redirectStrategy(RedirectStrategy redirectStrategy) {
ChannelSecurityConfigurer.this.redirectStrategy = redirectStrategy;
return this;
}
/**
* Return the {@link SecurityBuilder} when done using the
* {@link SecurityConfigurer}. This is useful for method chaining.
@@ -237,8 +237,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Gets the default {@link AccessDeniedHandler} from the
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler(HttpSecurityBuilder)} or
* create a {@link AccessDeniedHandlerImpl} if not available.
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler()} or create a
* {@link AccessDeniedHandlerImpl} if not available.
* @param http the {@link HttpSecurityBuilder}
* @return the {@link AccessDeniedHandler}
*/
@@ -247,7 +247,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
ExceptionHandlingConfigurer<H> exceptionConfig = http.getConfigurer(ExceptionHandlingConfigurer.class);
AccessDeniedHandler handler = null;
if (exceptionConfig != null) {
handler = exceptionConfig.getAccessDeniedHandler(http);
handler = exceptionConfig.getAccessDeniedHandler();
}
if (handler == null) {
handler = new AccessDeniedHandlerImpl();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -22,7 +22,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter;
@@ -30,7 +30,7 @@ import org.springframework.security.web.csrf.CsrfToken;
/**
* Adds a Filter that will generate a login page if one is not specified otherwise when
* using {@link EnableWebSecurity}.
* using {@link WebSecurityConfigurerAdapter}.
*
* <p>
* By default an
@@ -64,7 +64,7 @@ import org.springframework.security.web.csrf.CsrfToken;
*
* @author Rob Winch
* @since 3.2
* @see EnableWebSecurity
* @see WebSecurityConfigurerAdapter
*/
public final class DefaultLoginPageConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<DefaultLoginPageConfigurer<H>, H> {
@@ -369,7 +369,9 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
}
/**
* Specify that URLs requires a specific IP Address or subnet.
* Specify that URLs requires a specific IP Address or <a href=
* "https://forum.spring.io/showthread.php?102783-How-to-use-hasIpAddress&p=343971#post343971"
* >subnet</a>.
* @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
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2013 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.
@@ -18,7 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler;
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
@@ -84,15 +84,15 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* <p>
* Specifies the URL to send users to if login is required. If used with
* {@link EnableWebSecurity} a default login page will be generated when this
* attribute is not specified.
* {@link WebSecurityConfigurerAdapter} a default login page will be generated when
* this attribute is not specified.
* </p>
*
* <p>
* If a URL is specified or this is not being used in conjunction with
* {@link EnableWebSecurity}, users are required to process the specified URL to
* generate a login page. In general, the login page should create a form that submits
* a request with the following requirements to work with
* {@link WebSecurityConfigurerAdapter}, users are required to process the specified
* URL to generate a login page. In general, the login page should create a form that
* submits a request with the following requirements to work with
* {@link UsernamePasswordAuthenticationFilter}:
* </p>
*
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,14 +26,11 @@ import javax.servlet.http.HttpServletRequest;
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.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.header.HeaderWriter;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
import org.springframework.security.web.header.writers.HstsHeaderWriter;
@@ -50,7 +47,7 @@ import org.springframework.util.Assert;
/**
* <p>
* Adds the Security HTTP headers to the response. Security HTTP headers is activated by
* default when using {@link EnableWebSecurity}'s default constructor.
* default when using {@link WebSecurityConfigurerAdapter}'s default constructor.
* </p>
*
* <p>
@@ -100,12 +97,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
private final PermissionsPolicyConfig permissionsPolicy = new PermissionsPolicyConfig();
private final CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy = new CrossOriginOpenerPolicyConfig();
private final CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy = new CrossOriginEmbedderPolicyConfig();
private final CrossOriginResourcePolicyConfig crossOriginResourcePolicy = new CrossOriginResourcePolicyConfig();
/**
* Creates a new instance
*
@@ -401,9 +392,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
addIfNotNull(writers, this.referrerPolicy.writer);
addIfNotNull(writers, this.featurePolicy.writer);
addIfNotNull(writers, this.permissionsPolicy.writer);
addIfNotNull(writers, this.crossOriginOpenerPolicy.writer);
addIfNotNull(writers, this.crossOriginEmbedderPolicy.writer);
addIfNotNull(writers, this.crossOriginResourcePolicy.writer);
writers.addAll(this.headerWriters);
return writers;
}
@@ -556,129 +544,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
return this.permissionsPolicy;
}
/**
* 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
* @see CrossOriginOpenerPolicyHeaderWriter
*/
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">
* Cross-Origin-Opener-Policy</a> header.
* <p>
* Calling this method automatically enables (includes) the
* {@code Cross-Origin-Opener-Policy} header in the response using the supplied
* policy.
* <p>
* <p>
* Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which
* responsible for writing the header.
* </p>
* @return the {@link HeadersConfigurer} for additional customizations
* @since 5.7
* @see CrossOriginOpenerPolicyHeaderWriter
*/
public HeadersConfigurer<H> crossOriginOpenerPolicy(
Customizer<CrossOriginOpenerPolicyConfig> crossOriginOpenerPolicyCustomizer) {
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
crossOriginOpenerPolicyCustomizer.customize(this.crossOriginOpenerPolicy);
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
* @see CrossOriginEmbedderPolicyHeaderWriter
*/
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">
* Cross-Origin-Embedder-Policy</a> header.
* <p>
* Calling this method automatically enables (includes) the
* {@code Cross-Origin-Embedder-Policy} header in the response using the supplied
* policy.
* <p>
* <p>
* Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter}
* which is responsible for writing the header.
* </p>
* @return the {@link HeadersConfigurer} for additional customizations
* @since 5.7
* @see CrossOriginEmbedderPolicyHeaderWriter
*/
public HeadersConfigurer<H> crossOriginEmbedderPolicy(
Customizer<CrossOriginEmbedderPolicyConfig> crossOriginEmbedderPolicyCustomizer) {
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
crossOriginEmbedderPolicyCustomizer.customize(this.crossOriginEmbedderPolicy);
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
* @see CrossOriginResourcePolicyHeaderWriter
*/
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">
* Cross-Origin-Resource-Policy</a> header.
* <p>
* Calling this method automatically enables (includes) the
* {@code Cross-Origin-Resource-Policy} header in the response using the supplied
* policy.
* <p>
* <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
* @see CrossOriginResourcePolicyHeaderWriter
*/
public HeadersConfigurer<H> crossOriginResourcePolicy(
Customizer<CrossOriginResourcePolicyConfig> crossOriginResourcePolicyCustomizer) {
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
crossOriginResourcePolicyCustomizer.customize(this.crossOriginResourcePolicy);
return HeadersConfigurer.this;
}
public final class ContentTypeOptionsConfig {
private XContentTypeOptionsHeaderWriter writer;
@@ -1277,96 +1142,4 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
}
public final class CrossOriginOpenerPolicyConfig {
private CrossOriginOpenerPolicyHeaderWriter writer;
public CrossOriginOpenerPolicyConfig() {
}
/**
* Sets the policy to be used in the {@code Cross-Origin-Opener-Policy} header
* @param openerPolicy a {@code Cross-Origin-Opener-Policy}
* @return the {@link CrossOriginOpenerPolicyConfig} for additional configuration
* @throws IllegalArgumentException if openerPolicy is null
*/
public CrossOriginOpenerPolicyConfig policy(
CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy openerPolicy) {
this.writer.setPolicy(openerPolicy);
return this;
}
/**
* Allows completing configuration of Cross Origin Opener Policy and continuing
* configuration of headers.
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
return HeadersConfigurer.this;
}
}
public final class CrossOriginEmbedderPolicyConfig {
private CrossOriginEmbedderPolicyHeaderWriter writer;
public CrossOriginEmbedderPolicyConfig() {
}
/**
* Sets the policy to be used in the {@code Cross-Origin-Embedder-Policy} header
* @param embedderPolicy a {@code Cross-Origin-Embedder-Policy}
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional
* configuration
* @throws IllegalArgumentException if embedderPolicy is null
*/
public CrossOriginEmbedderPolicyConfig policy(
CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy embedderPolicy) {
this.writer.setPolicy(embedderPolicy);
return this;
}
/**
* Allows completing configuration of Cross-Origin-Embedder-Policy and continuing
* configuration of headers.
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
return HeadersConfigurer.this;
}
}
public final class CrossOriginResourcePolicyConfig {
private CrossOriginResourcePolicyHeaderWriter writer;
public CrossOriginResourcePolicyConfig() {
}
/**
* Sets the policy to be used in the {@code Cross-Origin-Resource-Policy} header
* @param resourcePolicy a {@code Cross-Origin-Resource-Policy}
* @return the {@link CrossOriginResourcePolicyConfig} for additional
* configuration
* @throws IllegalArgumentException if resourcePolicy is null
*/
public CrossOriginResourcePolicyConfig policy(
CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy resourcePolicy) {
this.writer.setPolicy(resourcePolicy);
return this;
}
/**
* Allows completing configuration of Cross-Origin-Resource-Policy and continuing
* configuration of headers.
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
return HeadersConfigurer.this;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2013 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.
@@ -48,22 +48,11 @@ final class PermitAllSupport {
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(configurer != null, "permitAll only works with HttpSecurity.authorizeRequests()");
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, AuthorizeHttpRequestsConfigurer.permitAllAuthorizationManager);
}
configurer.getRegistry().addMapping(0, new UrlMapping(matcher,
SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,12 +18,12 @@ package org.springframework.security.config.annotation.web.configurers;
import java.util.UUID;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.RememberMeAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
@@ -148,10 +148,11 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Specifies the {@link UserDetailsService} used to look up the {@link UserDetails}
* when a remember me token is valid. When using a
* {@link org.springframework.security.web.SecurityFilterChain} bean, the default is
* to look for a {@link UserDetailsService} bean. Alternatively, one can populate
* {@link #rememberMeServices(RememberMeServices)}.
* when a remember me token is valid. The default is to use the
* {@link UserDetailsService} found by invoking
* {@link HttpSecurity#getSharedObject(Class)} which is set when using
* {@link WebSecurityConfigurerAdapter#configure(AuthenticationManagerBuilder)}.
* Alternatively, one can populate {@link #rememberMeServices(RememberMeServices)}.
* @param userDetailsService the {@link UserDetailsService} to configure
* @return the {@link RememberMeConfigurer} for further customization
* @see AbstractRememberMeServices
@@ -394,16 +395,15 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
}
/**
* Gets the {@link UserDetailsService} to use. Either the explicitly configured
* {@link UserDetailsService} from {@link #userDetailsService(UserDetailsService)}, a
* shared object from {@link HttpSecurity#getSharedObject(Class)} or the
* {@link UserDetailsService} bean.
* Gets the {@link UserDetailsService} to use. Either the explicitly configure
* {@link UserDetailsService} from {@link #userDetailsService(UserDetailsService)} or
* a shared object from {@link HttpSecurity#getSharedObject(Class)}.
* @param http {@link HttpSecurity} to get the shared {@link UserDetailsService}
* @return the {@link UserDetailsService} to use
*/
private UserDetailsService getUserDetailsService(H http) {
if (this.userDetailsService == null) {
this.userDetailsService = getSharedOrBean(http, UserDetailsService.class);
this.userDetailsService = http.getSharedObject(UserDetailsService.class);
}
Assert.state(this.userDetailsService != null,
() -> "userDetailsService cannot be null. Invoke " + RememberMeConfigurer.class.getSimpleName()
@@ -431,25 +431,4 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
return this.key;
}
private <C> C getSharedOrBean(H http, Class<C> type) {
C shared = http.getSharedObject(type);
if (shared != null) {
return shared;
}
return getBeanOrNull(type);
}
private <T> T getBeanOrNull(Class<T> type) {
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
if (context == null) {
return null;
}
try {
return context.getBean(type);
}
catch (NoSuchBeanDefinitionException ex) {
return null;
}
}
}
@@ -22,10 +22,8 @@ import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextHolderFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
/**
* Allows persisting and restoring of the {@link SecurityContext} found on the
@@ -64,8 +62,6 @@ import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<SecurityContextConfigurer<H>, H> {
private boolean requireExplicitSave;
/**
* Creates a new instance
* @see HttpSecurity#securityContext()
@@ -83,46 +79,23 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
return this;
}
public SecurityContextConfigurer<H> requireExplicitSave(boolean requireExplicitSave) {
this.requireExplicitSave = requireExplicitSave;
return this;
}
boolean isRequireExplicitSave() {
return this.requireExplicitSave;
}
SecurityContextRepository getSecurityContextRepository() {
SecurityContextRepository securityContextRepository = getBuilder()
.getSharedObject(SecurityContextRepository.class);
if (securityContextRepository == null) {
securityContextRepository = new HttpSessionSecurityContextRepository();
}
return securityContextRepository;
}
@Override
@SuppressWarnings("unchecked")
public void configure(H http) {
SecurityContextRepository securityContextRepository = getSecurityContextRepository();
if (this.requireExplicitSave) {
SecurityContextHolderFilter securityContextHolderFilter = postProcess(
new SecurityContextHolderFilter(securityContextRepository));
http.addFilter(securityContextHolderFilter);
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
if (securityContextRepository == null) {
securityContextRepository = new HttpSessionSecurityContextRepository();
}
else {
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
securityContextRepository);
SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
SessionCreationPolicy sessionCreationPolicy = (sessionManagement != null)
? sessionManagement.getSessionCreationPolicy() : null;
if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {
securityContextFilter.setForceEagerSessionCreation(true);
http.addFilter(postProcess(new ForceEagerSessionCreationFilter()));
}
securityContextFilter = postProcess(securityContextFilter);
http.addFilter(securityContextFilter);
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
securityContextRepository);
SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
SessionCreationPolicy sessionCreationPolicy = (sessionManagement != null)
? sessionManagement.getSessionCreationPolicy() : null;
if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {
securityContextFilter.setForceEagerSessionCreation(true);
}
securityContextFilter = postProcess(securityContextFilter);
http.addFilter(securityContextFilter);
}
}
@@ -52,8 +52,6 @@ import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.security.web.session.SessionManagementFilter;
@@ -203,12 +201,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* {@link HttpServletResponse#encodeRedirectURL(String)} or
* {@link HttpServletResponse#encodeURL(String)}, otherwise disallows HTTP sessions to
* be included in the URL. This prevents leaking information to external domains.
* <p>
* This is achieved by guarding {@link HttpServletResponse#encodeURL} and
* {@link HttpServletResponse#encodeRedirectURL} invocations. Any code that also
* overrides either of these two methods, like
* {@link org.springframework.web.servlet.resource.ResourceUrlEncodingFilter}, needs
* to come after the security filter chain or risk being skipped.
* @param enableSessionUrlRewriting true if should allow the JSESSIONID to be
* rewritten into the URLs, else false (default)
* @return the {@link SessionManagementConfigurer} for further customization
@@ -378,12 +370,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
concurrentSessionFilter = postProcess(concurrentSessionFilter);
http.addFilter(concurrentSessionFilter);
}
if (!this.enableSessionUrlRewriting) {
http.addFilter(new DisableEncodeUrlFilter());
}
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
http.addFilter(new ForceEagerSessionCreationFilter());
}
}
private ConcurrentSessionFilter createConcurrencyFilter(H http) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,8 +18,6 @@ package org.springframework.security.config.annotation.web.configurers;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
@@ -142,7 +140,8 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
/**
* Specifies the {@link AuthenticationUserDetailsService} to use. If not specified,
* then the {@link UserDetailsService} bean will be used by default.
* the shared {@link UserDetailsService} will be used to create a
* {@link UserDetailsByNameServiceWrapper}.
* @param authenticationUserDetailsService the
* {@link AuthenticationUserDetailsService} to use
* @return the {@link X509Configurer} for further customizations
@@ -201,30 +200,9 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> getAuthenticationUserDetailsService(
H http) {
if (this.authenticationUserDetailsService == null) {
userDetailsService(getSharedOrBean(http, UserDetailsService.class));
userDetailsService(http.getSharedObject(UserDetailsService.class));
}
return this.authenticationUserDetailsService;
}
private <C> C getSharedOrBean(H http, Class<C> type) {
C shared = http.getSharedObject(type);
if (shared != null) {
return shared;
}
return getBeanOrNull(type);
}
private <T> T getBeanOrNull(Class<T> type) {
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
if (context == null) {
return null;
}
try {
return context.getBean(type);
}
catch (NoSuchBeanDefinitionException ex) {
return null;
}
}
}
@@ -18,9 +18,6 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.se
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import javax.servlet.http.HttpServletRequest;
@@ -28,7 +25,6 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.context.ApplicationContext;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationManagerResolver;
@@ -55,9 +51,6 @@ import org.springframework.security.oauth2.server.resource.web.DefaultBearerToke
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
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.csrf.CsrfException;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
@@ -160,19 +153,12 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
private OpaqueTokenConfigurer opaqueTokenConfigurer;
private AccessDeniedHandler accessDeniedHandler = new DelegatingAccessDeniedHandler(
new LinkedHashMap<>(createAccessDeniedHandlers()), new BearerTokenAccessDeniedHandler());
private AccessDeniedHandler accessDeniedHandler = new BearerTokenAccessDeniedHandler();
private AuthenticationEntryPoint authenticationEntryPoint = new BearerTokenAuthenticationEntryPoint();
private BearerTokenRequestMatcher requestMatcher = new BearerTokenRequestMatcher();
private static Map<Class<? extends AccessDeniedException>, AccessDeniedHandler> createAccessDeniedHandlers() {
Map<Class<? extends AccessDeniedException>, AccessDeniedHandler> handlers = new HashMap<>();
handlers.put(CsrfException.class, new AccessDeniedHandlerImpl());
return handlers;
}
public OAuth2ResourceServerConfigurer(ApplicationContext context) {
Assert.notNull(context, "context cannot be null");
this.context = context;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ 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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
@@ -61,29 +61,29 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
* <h2>Example Configuration</h2>
*
* <pre>
*
* &#064;Configuration
* &#064;EnableWebSecurity
* public class OpenIDLoginConfig {
* public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* &#064;Override
* protected void configure(HttpSecurity http) {
* http
* .authorizeRequests()
* .antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;)
* .and()
* .openidLogin()
* .permitAll();
* return http.build();
* }
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user);
* &#064;Override
* protected void configure(AuthenticationManagerBuilder auth)(
* AuthenticationManagerBuilder auth) throws Exception {
* auth
* .inMemoryAuthentication()
* .withUser(&quot;https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;);
* }
* }
* </pre>
@@ -229,14 +229,14 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>>
/**
* <p>
* Specifies the URL to send users to if login is required. If used with
* {@link EnableWebSecurity} a default login page will be generated when this
* attribute is not specified.
* {@link WebSecurityConfigurerAdapter} a default login page will be generated when
* this attribute is not specified.
* </p>
*
* <p>
* If a URL is specified or this is not being used in conjunction with
* {@link EnableWebSecurity}, users are required to process the specified URL to
* generate a login page.
* {@link WebSecurityConfigurerAdapter}, users are required to process the specified
* URL to generate a login page.
* </p>
*
* <ul>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -19,6 +19,8 @@ package org.springframework.security.config.annotation.web.configurers.saml2;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.opensaml.core.Version;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -48,7 +50,6 @@ import org.springframework.security.saml2.provider.service.web.RelyingPartyRegis
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestContextResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
@@ -114,12 +115,10 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
private String loginPage;
private String authenticationRequestUri = "/saml2/authenticate/{registrationId}";
private Saml2AuthenticationRequestResolver authenticationRequestResolver;
private String loginProcessingUrl = Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
private AuthenticationRequestEndpointConfig authenticationRequestEndpoint = new AuthenticationRequestEndpointConfig();
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
private AuthenticationConverter authenticationConverter;
@@ -177,20 +176,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
return this;
}
/**
* Use this {@link Saml2AuthenticationRequestResolver} for generating SAML 2.0
* Authentication Requests.
* @param authenticationRequestResolver
* @return the {@link Saml2LoginConfigurer} for further configuration
* @since 5.7
*/
public Saml2LoginConfigurer<B> authenticationRequestResolver(
Saml2AuthenticationRequestResolver authenticationRequestResolver) {
Assert.notNull(authenticationRequestResolver, "authenticationRequestResolver cannot be null");
this.authenticationRequestResolver = authenticationRequestResolver;
return this;
}
/**
* Specifies the URL to validate the credentials. If specified a custom URL, consider
* specifying a custom {@link AuthenticationConverter} via
@@ -215,7 +200,7 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
/**
* {@inheritDoc}
* <p>
*
* Initializes this filter chain for SAML 2 Login. The following actions are taken:
* <ul>
* <li>The WebSSO endpoint has CSRF disabled, typically {@code /login/saml2/sso}</li>
@@ -241,8 +226,8 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
super.init(http);
}
else {
Map<String, String> providerUrlMap = getIdentityProviderUrlMap(this.authenticationRequestUri,
this.relyingPartyRegistrationRepository);
Map<String, String> providerUrlMap = getIdentityProviderUrlMap(
this.authenticationRequestEndpoint.filterProcessingUrl, this.relyingPartyRegistrationRepository);
boolean singleProvider = providerUrlMap.size() == 1;
if (singleProvider) {
// Setup auto-redirect to provider login page
@@ -262,16 +247,14 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
/**
* {@inheritDoc}
* <p>
*
* During the {@code configure} phase, a
* {@link Saml2WebSsoAuthenticationRequestFilter} is added to handle SAML 2.0
* AuthNRequest redirects
*/
@Override
public void configure(B http) throws Exception {
Saml2WebSsoAuthenticationRequestFilter filter = getAuthenticationRequestFilter(http);
filter.setAuthenticationRequestRepository(getAuthenticationRequestRepository(http));
http.addFilter(postProcess(filter));
http.addFilter(this.authenticationRequestEndpoint.build(http));
super.configure(http);
if (this.authenticationManager == null) {
registerDefaultAuthenticationProvider(http);
@@ -281,11 +264,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
}
}
private RelyingPartyRegistrationResolver relyingPartyRegistrationResolver(B http) {
RelyingPartyRegistrationRepository registrations = relyingPartyRegistrationRepository(http);
return new DefaultRelyingPartyRegistrationResolver(registrations);
}
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository(B http) {
if (this.relyingPartyRegistrationRepository == null) {
this.relyingPartyRegistrationRepository = getSharedOrBean(http, RelyingPartyRegistrationRepository.class);
@@ -298,46 +276,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
saml2WebSsoAuthenticationFilter.setAuthenticationRequestRepository(getAuthenticationRequestRepository(http));
}
private Saml2WebSsoAuthenticationRequestFilter getAuthenticationRequestFilter(B http) {
Saml2AuthenticationRequestResolver authenticationRequestResolver = getAuthenticationRequestResolver(http);
if (authenticationRequestResolver != null) {
return new Saml2WebSsoAuthenticationRequestFilter(authenticationRequestResolver);
}
return new Saml2WebSsoAuthenticationRequestFilter(getAuthenticationRequestContextResolver(http),
getAuthenticationRequestFactory(http));
}
private Saml2AuthenticationRequestResolver getAuthenticationRequestResolver(B http) {
if (this.authenticationRequestResolver != null) {
return this.authenticationRequestResolver;
}
return getBeanOrNull(http, Saml2AuthenticationRequestResolver.class);
}
private Saml2AuthenticationRequestFactory getAuthenticationRequestFactory(B http) {
Saml2AuthenticationRequestFactory resolver = getSharedOrBean(http, Saml2AuthenticationRequestFactory.class);
if (resolver != null) {
return resolver;
}
if (version().startsWith("4")) {
return new OpenSaml4AuthenticationRequestFactory();
}
else {
return new OpenSamlAuthenticationRequestFactory();
}
}
private Saml2AuthenticationRequestContextResolver getAuthenticationRequestContextResolver(B http) {
Saml2AuthenticationRequestContextResolver resolver = getBeanOrNull(http,
Saml2AuthenticationRequestContextResolver.class);
if (resolver != null) {
return resolver;
}
RelyingPartyRegistrationResolver registrationResolver = new DefaultRelyingPartyRegistrationResolver(
this.relyingPartyRegistrationRepository);
return new DefaultSaml2AuthenticationRequestContextResolver(registrationResolver);
}
private AuthenticationConverter getAuthenticationConverter(B http) {
if (this.authenticationConverter != null) {
return this.authenticationConverter;
@@ -386,8 +324,8 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
return;
}
loginPageGeneratingFilter.setSaml2LoginEnabled(true);
loginPageGeneratingFilter.setSaml2AuthenticationUrlToProviderName(
this.getIdentityProviderUrlMap(this.authenticationRequestUri, this.relyingPartyRegistrationRepository));
loginPageGeneratingFilter.setSaml2AuthenticationUrlToProviderName(this.getIdentityProviderUrlMap(
this.authenticationRequestEndpoint.filterProcessingUrl, this.relyingPartyRegistrationRepository));
loginPageGeneratingFilter.setLoginPageUrl(this.getLoginPage());
loginPageGeneratingFilter.setFailureUrl(this.getFailureUrl());
}
@@ -441,4 +379,46 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
}
}
private final class AuthenticationRequestEndpointConfig {
private String filterProcessingUrl = "/saml2/authenticate/{registrationId}";
private AuthenticationRequestEndpointConfig() {
}
private Filter build(B http) {
Saml2AuthenticationRequestFactory authenticationRequestResolver = getResolver(http);
Saml2AuthenticationRequestContextResolver contextResolver = getContextResolver(http);
Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> repository = getAuthenticationRequestRepository(
http);
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(contextResolver,
authenticationRequestResolver);
filter.setAuthenticationRequestRepository(repository);
return postProcess(filter);
}
private Saml2AuthenticationRequestFactory getResolver(B http) {
Saml2AuthenticationRequestFactory resolver = getSharedOrBean(http, Saml2AuthenticationRequestFactory.class);
if (resolver == null) {
if (version().startsWith("4")) {
return new OpenSaml4AuthenticationRequestFactory();
}
return new OpenSamlAuthenticationRequestFactory();
}
return resolver;
}
private Saml2AuthenticationRequestContextResolver getContextResolver(B http) {
Saml2AuthenticationRequestContextResolver resolver = getBeanOrNull(http,
Saml2AuthenticationRequestContextResolver.class);
if (resolver == null) {
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(
Saml2LoginConfigurer.this.relyingPartyRegistrationRepository);
return new DefaultSaml2AuthenticationRequestContextResolver(relyingPartyRegistrationResolver);
}
return resolver;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
@@ -42,7 +41,6 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve
* This {@code Configuration} is imported by {@link EnableWebFluxSecurity}
*
* @author Rob Winch
* @author Alavudin Kuttikkattil
* @since 5.1
*/
final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
@@ -66,12 +64,14 @@ final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
private ReactiveOAuth2AuthorizedClientService authorizedClientService;
private ReactiveOAuth2AuthorizedClientManager authorizedClientManager;
@Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
ReactiveOAuth2AuthorizedClientManager authorizedClientManager = getAuthorizedClientManager();
if (authorizedClientManager != null) {
if (this.authorizedClientRepository != null && this.clientRegistrationRepository != null) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
.builder().authorizationCode().refreshToken().clientCredentials().password().build();
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
this.clientRegistrationRepository, getAuthorizedClientRepository());
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
configurer.addCustomResolver(new OAuth2AuthorizedClientArgumentResolver(authorizedClientManager));
}
}
@@ -93,13 +93,6 @@ final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
}
}
@Autowired(required = false)
void setAuthorizedClientManager(List<ReactiveOAuth2AuthorizedClientManager> authorizedClientManager) {
if (authorizedClientManager.size() == 1) {
this.authorizedClientManager = authorizedClientManager.get(0);
}
}
private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() {
if (this.authorizedClientRepository != null) {
return this.authorizedClientRepository;
@@ -110,23 +103,6 @@ final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
return null;
}
private ReactiveOAuth2AuthorizedClientManager getAuthorizedClientManager() {
if (this.authorizedClientManager != null) {
return this.authorizedClientManager;
}
ReactiveOAuth2AuthorizedClientManager authorizedClientManager = null;
if (this.authorizedClientRepository != null && this.clientRegistrationRepository != null) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
.builder().authorizationCode().refreshToken().clientCredentials().password().build();
DefaultReactiveOAuth2AuthorizedClientManager defaultReactiveOAuth2AuthorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
this.clientRegistrationRepository, getAuthorizedClientRepository());
defaultReactiveOAuth2AuthorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
authorizedClientManager = defaultReactiveOAuth2AuthorizedClientManager;
}
return authorizedClientManager;
}
}
}
@@ -102,9 +102,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
pc.getRegistry().registerAlias(id, alias);
pc.getReaderContext().fireAliasRegistered(id, alias, pc.extractSource(element));
}
if (!BeanIds.AUTHENTICATION_MANAGER.equals(id)
&& !pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)
&& !pc.getRegistry().isAlias(BeanIds.AUTHENTICATION_MANAGER)) {
if (!BeanIds.AUTHENTICATION_MANAGER.equals(id)) {
pc.getRegistry().registerAlias(id, BeanIds.AUTHENTICATION_MANAGER);
pc.getReaderContext().fireAliasRegistered(id, BeanIds.AUTHENTICATION_MANAGER, pc.extractSource(element));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2020 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.
@@ -164,8 +164,6 @@ final class AuthenticationConfigBuilder {
@SuppressWarnings("rawtypes")
private ManagedList logoutHandlers;
private BeanMetadataElement logoutSuccessHandler;
private BeanDefinition loginPageGenerationFilter;
private BeanDefinition logoutPageGenerationFilter;
@@ -204,20 +202,6 @@ final class AuthenticationConfigBuilder {
private BeanDefinition oauth2LoginLinks;
private BeanDefinition saml2AuthenticationUrlToProviderName;
private BeanDefinition saml2AuthorizationRequestFilter;
private String saml2AuthenticationFilterId;
private String saml2AuthenticationRequestFilterId;
private String saml2LogoutFilterId;
private String saml2LogoutRequestFilterId;
private String saml2LogoutResponseFilterId;
private boolean oauth2ClientEnabled;
private BeanDefinition authorizationRequestRedirectFilter;
@@ -236,8 +220,8 @@ final class AuthenticationConfigBuilder {
AuthenticationConfigBuilder(Element element, boolean forceAutoConfig, ParserContext pc,
SessionCreationPolicy sessionPolicy, BeanReference requestCache, BeanReference authenticationManager,
BeanReference authenticationFilterSecurityContextRepositoryRef, BeanReference sessionStrategy,
BeanReference portMapper, BeanReference portResolver, BeanMetadataElement csrfLogoutHandler) {
BeanReference sessionStrategy, BeanReference portMapper, BeanReference portResolver,
BeanMetadataElement csrfLogoutHandler) {
this.httpElt = element;
this.pc = pc;
this.requestCache = requestCache;
@@ -251,16 +235,12 @@ final class AuthenticationConfigBuilder {
createRememberMeFilter(authenticationManager);
createBasicFilter(authenticationManager);
createBearerTokenAuthenticationFilter(authenticationManager);
createFormLoginFilter(sessionStrategy, authenticationManager, authenticationFilterSecurityContextRepositoryRef);
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager,
authenticationFilterSecurityContextRepositoryRef);
createOpenIDLoginFilter(sessionStrategy, authenticationManager,
authenticationFilterSecurityContextRepositoryRef);
createSaml2LoginFilter(authenticationManager, authenticationFilterSecurityContextRepositoryRef);
createFormLoginFilter(sessionStrategy, authenticationManager);
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager);
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
createX509Filter(authenticationManager);
createJeeFilter(authenticationManager);
createLogoutFilter();
createSaml2LogoutFilter();
createLoginPageFilterIfNeeded();
createUserDetailsServiceFactory();
createExceptionTranslationFilter();
@@ -292,8 +272,7 @@ final class AuthenticationConfigBuilder {
this.rememberMeProviderRef = new RuntimeBeanReference(id);
}
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager,
BeanReference authenticationFilterSecurityContextRepositoryRef) {
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element formLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.FORM_LOGIN);
RootBeanDefinition formFilter = null;
if (formLoginElt != null || this.autoConfig) {
@@ -309,10 +288,6 @@ final class AuthenticationConfigBuilder {
if (formFilter != null) {
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", this.allowSessionCreation);
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
if (authenticationFilterSecurityContextRepositoryRef != null) {
formFilter.getPropertyValues().addPropertyValue("securityContextRepository",
authenticationFilterSecurityContextRepositoryRef);
}
// Id is required by login page filter
this.formFilterId = this.pc.getReaderContext().generateBeanName(formFilter);
this.pc.registerBeanComponent(new BeanComponentDefinition(formFilter, this.formFilterId));
@@ -321,15 +296,13 @@ final class AuthenticationConfigBuilder {
}
void createOAuth2ClientFilters(BeanReference sessionStrategy, BeanReference requestCache,
BeanReference authenticationManager, BeanReference authenticationFilterSecurityContextRepositoryRef) {
createOAuth2LoginFilter(sessionStrategy, authenticationManager,
authenticationFilterSecurityContextRepositoryRef);
createOAuth2ClientFilter(requestCache, authenticationManager, authenticationFilterSecurityContextRepositoryRef);
BeanReference authenticationManager) {
createOAuth2LoginFilter(sessionStrategy, authenticationManager);
createOAuth2ClientFilter(requestCache, authenticationManager);
registerOAuth2ClientPostProcessors();
}
void createOAuth2LoginFilter(BeanReference sessionStrategy, BeanReference authManager,
BeanReference authenticationFilterSecurityContextRepositoryRef) {
void createOAuth2LoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element oauth2LoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OAUTH2_LOGIN);
if (oauth2LoginElt == null) {
return;
@@ -341,10 +314,6 @@ final class AuthenticationConfigBuilder {
BeanDefinition defaultAuthorizedClientRepository = parser.getDefaultAuthorizedClientRepository();
registerDefaultAuthorizedClientRepositoryIfNecessary(defaultAuthorizedClientRepository);
oauth2LoginFilterBean.getPropertyValues().addPropertyValue("authenticationManager", authManager);
if (authenticationFilterSecurityContextRepositoryRef != null) {
oauth2LoginFilterBean.getPropertyValues().addPropertyValue("securityContextRepository",
authenticationFilterSecurityContextRepositoryRef);
}
// retrieve the other bean result
BeanDefinition oauth2LoginAuthProvider = parser.getOAuth2LoginAuthenticationProvider();
@@ -374,15 +343,14 @@ final class AuthenticationConfigBuilder {
this.oauth2LoginOidcAuthenticationProviderRef = new RuntimeBeanReference(oauth2LoginOidcAuthProviderId);
}
void createOAuth2ClientFilter(BeanReference requestCache, BeanReference authenticationManager,
BeanReference authenticationFilterSecurityContextRepositoryRef) {
void createOAuth2ClientFilter(BeanReference requestCache, BeanReference authenticationManager) {
Element oauth2ClientElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OAUTH2_CLIENT);
if (oauth2ClientElt == null) {
return;
}
this.oauth2ClientEnabled = true;
OAuth2ClientBeanDefinitionParser parser = new OAuth2ClientBeanDefinitionParser(requestCache,
authenticationManager, authenticationFilterSecurityContextRepositoryRef);
authenticationManager);
parser.parse(oauth2ClientElt, this.pc);
BeanDefinition defaultAuthorizedClientRepository = parser.getDefaultAuthorizedClientRepository();
registerDefaultAuthorizedClientRepositoryIfNecessary(defaultAuthorizedClientRepository);
@@ -427,8 +395,7 @@ final class AuthenticationConfigBuilder {
}
}
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager,
BeanReference authenticationFilterSecurityContextRepositoryRef) {
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element openIDLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OPENID_LOGIN);
RootBeanDefinition openIDFilter = null;
if (openIDLoginElt != null) {
@@ -437,10 +404,6 @@ final class AuthenticationConfigBuilder {
if (openIDFilter != null) {
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", this.allowSessionCreation);
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
if (authenticationFilterSecurityContextRepositoryRef != null) {
openIDFilter.getPropertyValues().addPropertyValue("securityContextRepository",
authenticationFilterSecurityContextRepositoryRef);
}
// Required by login page filter
this.openIDFilterId = this.pc.getReaderContext().generateBeanName(openIDFilter);
this.pc.registerBeanComponent(new BeanComponentDefinition(openIDFilter, this.openIDFilterId));
@@ -449,31 +412,6 @@ final class AuthenticationConfigBuilder {
}
}
private void createSaml2LoginFilter(BeanReference authenticationManager,
BeanReference authenticationFilterSecurityContextRepositoryRef) {
Element saml2LoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.SAML2_LOGIN);
if (saml2LoginElt == null) {
return;
}
Saml2LoginBeanDefinitionParser parser = new Saml2LoginBeanDefinitionParser(this.csrfIgnoreRequestMatchers,
this.portMapper, this.portResolver, this.requestCache, this.allowSessionCreation, authenticationManager,
authenticationFilterSecurityContextRepositoryRef, this.authenticationProviders,
this.defaultEntryPointMappings);
BeanDefinition saml2WebSsoAuthenticationFilter = parser.parse(saml2LoginElt, this.pc);
this.saml2AuthorizationRequestFilter = parser.getSaml2WebSsoAuthenticationRequestFilter();
this.saml2AuthenticationFilterId = this.pc.getReaderContext().generateBeanName(saml2WebSsoAuthenticationFilter);
this.saml2AuthenticationRequestFilterId = this.pc.getReaderContext()
.generateBeanName(this.saml2AuthorizationRequestFilter);
this.saml2AuthenticationUrlToProviderName = parser.getSaml2AuthenticationUrlToProviderName();
// register the component
this.pc.registerBeanComponent(
new BeanComponentDefinition(saml2WebSsoAuthenticationFilter, this.saml2AuthenticationFilterId));
this.pc.registerBeanComponent(new BeanComponentDefinition(this.saml2AuthorizationRequestFilter,
this.saml2AuthenticationRequestFilterId));
}
/**
* Parses OpenID 1.0 and 2.0 - related parts of configuration xmls
* @param sessionStrategy sessionStrategy
@@ -728,12 +666,6 @@ final class AuthenticationConfigBuilder {
loginPageFilter.addPropertyValue("Oauth2LoginEnabled", true);
loginPageFilter.addPropertyValue("Oauth2AuthenticationUrlToClientName", this.oauth2LoginLinks);
}
if (this.saml2AuthenticationFilterId != null) {
loginPageFilter.addConstructorArgReference(this.saml2AuthenticationFilterId);
loginPageFilter.addPropertyValue("saml2LoginEnabled", true);
loginPageFilter.addPropertyValue("saml2AuthenticationUrlToProviderName",
this.saml2AuthenticationUrlToProviderName);
}
this.loginPageGenerationFilter = loginPageFilter.getBeanDefinition();
this.logoutPageGenerationFilter = logoutPageFilter.getBeanDefinition();
}
@@ -750,33 +682,9 @@ final class AuthenticationConfigBuilder {
this.rememberMeServicesId, this.csrfLogoutHandler);
this.logoutFilter = logoutParser.parse(logoutElt, this.pc);
this.logoutHandlers = logoutParser.getLogoutHandlers();
this.logoutSuccessHandler = logoutParser.getLogoutSuccessHandler();
}
}
private void createSaml2LogoutFilter() {
Element saml2LogoutElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.SAML2_LOGOUT);
if (saml2LogoutElt == null) {
return;
}
Saml2LogoutBeanDefinitionParser parser = new Saml2LogoutBeanDefinitionParser(this.logoutHandlers,
this.logoutSuccessHandler);
parser.parse(saml2LogoutElt, this.pc);
BeanDefinition saml2LogoutFilter = parser.getLogoutFilter();
BeanDefinition saml2LogoutRequestFilter = parser.getLogoutRequestFilter();
BeanDefinition saml2LogoutResponseFilter = parser.getLogoutResponseFilter();
this.saml2LogoutFilterId = this.pc.getReaderContext().generateBeanName(saml2LogoutFilter);
this.saml2LogoutRequestFilterId = this.pc.getReaderContext().generateBeanName(saml2LogoutRequestFilter);
this.saml2LogoutResponseFilterId = this.pc.getReaderContext().generateBeanName(saml2LogoutResponseFilter);
// register the component
this.pc.registerBeanComponent(new BeanComponentDefinition(saml2LogoutFilter, this.saml2LogoutFilterId));
this.pc.registerBeanComponent(
new BeanComponentDefinition(saml2LogoutRequestFilter, this.saml2LogoutRequestFilterId));
this.pc.registerBeanComponent(
new BeanComponentDefinition(saml2LogoutResponseFilter, this.saml2LogoutResponseFilterId));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
ManagedList getLogoutHandlers() {
if (this.logoutHandlers == null && this.rememberMeProviderRef != null) {
@@ -932,8 +840,7 @@ final class AuthenticationConfigBuilder {
if (formLoginElt != null && this.oauth2LoginEntryPoint != null) {
return this.formEntryPoint;
}
// If form login was enabled through auto-config, and Oauth2 login & Saml2
// login was not
// If form login was enabled through auto-config, and Oauth2 login was not
// enabled then use form login
if (this.oauth2LoginEntryPoint == null) {
return this.formEntryPoint;
@@ -1016,20 +923,6 @@ final class AuthenticationConfigBuilder {
filters.add(new OrderDecorator(this.authorizationCodeGrantFilter,
SecurityFilters.OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER));
}
if (this.saml2AuthenticationFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2AuthenticationFilterId),
SecurityFilters.SAML2_AUTHENTICATION_FILTER));
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2AuthenticationRequestFilterId),
SecurityFilters.SAML2_AUTHENTICATION_REQUEST_FILTER));
}
if (this.saml2LogoutFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2LogoutFilterId),
SecurityFilters.SAML2_LOGOUT_FILTER));
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2LogoutRequestFilterId),
SecurityFilters.SAML2_LOGOUT_REQUEST_FILTER));
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2LogoutResponseFilterId),
SecurityFilters.SAML2_LOGOUT_RESPONSE_FILTER));
}
filters.add(new OrderDecorator(this.etf, SecurityFilters.EXCEPTION_TRANSLATION_FILTER));
return filters;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,9 +36,6 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
import org.springframework.security.web.header.writers.HstsHeaderWriter;
@@ -125,12 +122,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
private static final String PERMISSIONS_POLICY_ELEMENT = "permissions-policy";
private static final String CROSS_ORIGIN_OPENER_POLICY_ELEMENT = "cross-origin-opener-policy";
private static final String CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT = "cross-origin-embedder-policy";
private static final String CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT = "cross-origin-resource-policy";
private static final String ALLOW_FROM = "ALLOW-FROM";
private ManagedList<BeanMetadataElement> headerWriters;
@@ -153,9 +144,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
parseReferrerPolicyElement(element, parserContext);
parseFeaturePolicyElement(element, parserContext);
parsePermissionsPolicyElement(element, parserContext);
parseCrossOriginOpenerPolicy(disabled, element);
parseCrossOriginEmbedderPolicy(disabled, element);
parseCrossOriginResourcePolicy(disabled, element);
parseHeaderElements(element);
boolean noWriters = this.headerWriters.isEmpty();
if (disabled && !noWriters) {
@@ -388,75 +376,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
this.headerWriters.add(headersWriter.getBeanDefinition());
}
private void parseCrossOriginOpenerPolicy(boolean elementDisabled, Element element) {
if (elementDisabled || element == null) {
return;
}
CrossOriginOpenerPolicyHeaderWriter writer = new CrossOriginOpenerPolicyHeaderWriter();
Element crossOriginOpenerPolicyElement = DomUtils.getChildElementByTagName(element,
CROSS_ORIGIN_OPENER_POLICY_ELEMENT);
if (crossOriginOpenerPolicyElement != null) {
addCrossOriginOpenerPolicy(crossOriginOpenerPolicyElement, writer);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(CrossOriginOpenerPolicyHeaderWriter.class, () -> writer);
this.headerWriters.add(builder.getBeanDefinition());
}
private void parseCrossOriginEmbedderPolicy(boolean elementDisabled, Element element) {
if (elementDisabled || element == null) {
return;
}
CrossOriginEmbedderPolicyHeaderWriter writer = new CrossOriginEmbedderPolicyHeaderWriter();
Element crossOriginEmbedderPolicyElement = DomUtils.getChildElementByTagName(element,
CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT);
if (crossOriginEmbedderPolicyElement != null) {
addCrossOriginEmbedderPolicy(crossOriginEmbedderPolicyElement, writer);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(CrossOriginEmbedderPolicyHeaderWriter.class, () -> writer);
this.headerWriters.add(builder.getBeanDefinition());
}
private void parseCrossOriginResourcePolicy(boolean elementDisabled, Element element) {
if (elementDisabled || element == null) {
return;
}
CrossOriginResourcePolicyHeaderWriter writer = new CrossOriginResourcePolicyHeaderWriter();
Element crossOriginResourcePolicyElement = DomUtils.getChildElementByTagName(element,
CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT);
if (crossOriginResourcePolicyElement != null) {
addCrossOriginResourcePolicy(crossOriginResourcePolicyElement, writer);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(CrossOriginResourcePolicyHeaderWriter.class, () -> writer);
this.headerWriters.add(builder.getBeanDefinition());
}
private void addCrossOriginResourcePolicy(Element crossOriginResourcePolicyElement,
CrossOriginResourcePolicyHeaderWriter writer) {
String policy = crossOriginResourcePolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasText(policy)) {
writer.setPolicy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.from(policy));
}
}
private void addCrossOriginEmbedderPolicy(Element crossOriginEmbedderPolicyElement,
CrossOriginEmbedderPolicyHeaderWriter writer) {
String policy = crossOriginEmbedderPolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasText(policy)) {
writer.setPolicy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.from(policy));
}
}
private void addCrossOriginOpenerPolicy(Element crossOriginOpenerPolicyElement,
CrossOriginOpenerPolicyHeaderWriter writer) {
String policy = crossOriginOpenerPolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasText(policy)) {
writer.setPolicy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.from(policy));
}
}
private void attrNotAllowed(ParserContext context, String attrName, String otherAttrName, Element element) {
context.getReaderContext().error("Only one of '" + attrName + "' or '" + otherAttrName + "' can be set.",
element);
@@ -59,7 +59,6 @@ import org.springframework.security.web.authentication.session.RegisterSessionAu
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextHolderFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
@@ -68,8 +67,6 @@ import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy;
@@ -107,8 +104,6 @@ class HttpConfigurationBuilder {
private static final String ATT_SECURITY_CONTEXT_REPOSITORY = "security-context-repository-ref";
private static final String ATT_SECURITY_CONTEXT_EXPLICIT_SAVE = "security-context-explicit-save";
private static final String ATT_INVALID_SESSION_STRATEGY_REF = "invalid-session-strategy-ref";
private static final String ATT_DISABLE_URL_REWRITING = "disable-url-rewriting";
@@ -149,8 +144,6 @@ class HttpConfigurationBuilder {
private BeanDefinition securityContextPersistenceFilter;
private BeanDefinition forceEagerSessionCreationFilter;
private BeanReference contextRepoRef;
private BeanReference sessionRegistryRef;
@@ -183,8 +176,6 @@ class HttpConfigurationBuilder {
private BeanDefinition csrfFilter;
private BeanDefinition disableUrlRewriteFilter;
private BeanDefinition wellKnownChangePasswordRedirectFilter;
private BeanMetadataElement csrfLogoutHandler;
@@ -210,10 +201,8 @@ class HttpConfigurationBuilder {
String createSession = element.getAttribute(ATT_CREATE_SESSION);
this.sessionPolicy = !StringUtils.hasText(createSession) ? SessionCreationPolicy.IF_REQUIRED
: createPolicy(createSession);
createForceEagerSessionCreationFilter();
createDisableEncodeUrlFilter();
createCsrfFilter();
createSecurityPersistence();
createSecurityContextPersistenceFilter();
createSessionManagementFilters();
createWebAsyncManagerFilter();
createRequestCacheFilter();
@@ -289,51 +278,19 @@ class HttpConfigurationBuilder {
return lowerCase ? path.toLowerCase() : path;
}
BeanReference getSecurityContextRepositoryForAuthenticationFilters() {
return (isExplicitSave()) ? this.contextRepoRef : null;
}
private void createSecurityPersistence() {
createSecurityContextRepository();
if (isExplicitSave()) {
createSecurityContextHolderFilter();
}
else {
createSecurityContextPersistenceFilter();
}
}
private boolean isExplicitSave() {
String explicitSaveAttr = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_EXPLICIT_SAVE);
return Boolean.parseBoolean(explicitSaveAttr);
}
private void createForceEagerSessionCreationFilter() {
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
this.forceEagerSessionCreationFilter = new RootBeanDefinition(ForceEagerSessionCreationFilter.class);
}
}
private void createSecurityContextPersistenceFilter() {
BeanDefinitionBuilder scpf = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextPersistenceFilter.class);
switch (this.sessionPolicy) {
case ALWAYS:
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
break;
case NEVER:
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
break;
default:
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
}
scpf.addConstructorArgValue(this.contextRepoRef);
this.securityContextPersistenceFilter = scpf.getBeanDefinition();
}
private void createSecurityContextRepository() {
String repoRef = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_REPOSITORY);
if (!StringUtils.hasText(repoRef)) {
String disableUrlRewriting = this.httpElt.getAttribute(ATT_DISABLE_URL_REWRITING);
if (!StringUtils.hasText(disableUrlRewriting)) {
disableUrlRewriting = "true";
}
if (StringUtils.hasText(repoRef)) {
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
}
}
else {
BeanDefinitionBuilder contextRepo;
if (this.sessionPolicy == SessionCreationPolicy.STATELESS) {
contextRepo = BeanDefinitionBuilder.rootBeanDefinition(NullSecurityContextRepository.class);
@@ -343,14 +300,17 @@ class HttpConfigurationBuilder {
switch (this.sessionPolicy) {
case ALWAYS:
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
break;
case NEVER:
contextRepo.addPropertyValue("allowSessionCreation", Boolean.FALSE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
break;
default:
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
}
if (isDisableUrlRewriting()) {
if ("true".equals(disableUrlRewriting)) {
contextRepo.addPropertyValue("disableUrlRewriting", Boolean.TRUE);
}
}
@@ -360,17 +320,9 @@ class HttpConfigurationBuilder {
}
this.contextRepoRef = new RuntimeBeanReference(repoRef);
}
scpf.addConstructorArgValue(this.contextRepoRef);
private boolean isDisableUrlRewriting() {
String disableUrlRewriting = this.httpElt.getAttribute(ATT_DISABLE_URL_REWRITING);
return !"false".equals(disableUrlRewriting);
}
private void createSecurityContextHolderFilter() {
BeanDefinitionBuilder filter = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextHolderFilter.class);
filter.addConstructorArgValue(this.contextRepoRef);
this.securityContextPersistenceFilter = filter.getBeanDefinition();
this.securityContextPersistenceFilter = scpf.getBeanDefinition();
}
private void createSessionManagementFilters() {
@@ -733,12 +685,6 @@ class HttpConfigurationBuilder {
}
private void createDisableEncodeUrlFilter() {
if (isDisableUrlRewriting()) {
this.disableUrlRewriteFilter = new RootBeanDefinition(DisableEncodeUrlFilter.class);
}
}
private void createCsrfFilter() {
Element elmt = DomUtils.getChildElementByTagName(this.httpElt, Elements.CSRF);
this.csrfParser = new CsrfBeanDefinitionParser();
@@ -778,13 +724,6 @@ class HttpConfigurationBuilder {
List<OrderDecorator> getFilters() {
List<OrderDecorator> filters = new ArrayList<>();
if (this.forceEagerSessionCreationFilter != null) {
filters.add(new OrderDecorator(this.forceEagerSessionCreationFilter,
SecurityFilters.FORCE_EAGER_SESSION_FILTER));
}
if (this.disableUrlRewriteFilter != null) {
filters.add(new OrderDecorator(this.disableUrlRewriteFilter, SecurityFilters.DISABLE_ENCODE_URL_FILTER));
}
if (this.cpf != null) {
filters.add(new OrderDecorator(this.cpf, SecurityFilters.CHANNEL_FILTER));
}
@@ -144,11 +144,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
boolean forceAutoConfig = isDefaultHttpConfig(element);
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, forceAutoConfig, pc, portMapper,
portResolver, authenticationManager);
httpBldr.getSecurityContextRepositoryForAuthenticationFilters();
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, forceAutoConfig, pc,
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
httpBldr.getSecurityContextRepositoryForAuthenticationFilters(), httpBldr.getSessionStrategy(),
portMapper, portResolver, httpBldr.getCsrfLogoutHandler());
httpBldr.getSessionStrategy(), portMapper, portResolver, httpBldr.getCsrfLogoutHandler());
httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
httpBldr.setEntryPoint(authBldr.getEntryPointBean());
httpBldr.setAccessDeniedHandler(authBldr.getAccessDeniedHandlerBean());
@@ -59,8 +59,6 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
private boolean csrfEnabled;
private BeanMetadataElement logoutSuccessHandler;
LogoutBeanDefinitionParser(String loginPageUrl, String rememberMeServices, BeanMetadataElement csrfLogoutHandler) {
this.defaultLogoutUrl = loginPageUrl + "?logout";
this.rememberMeServices = rememberMeServices;
@@ -100,7 +98,6 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
pc.extractSource(element));
}
builder.addConstructorArgReference(successHandlerRef);
this.logoutSuccessHandler = new RuntimeBeanReference(successHandlerRef);
}
else {
// Use the logout URL if no handler set
@@ -140,8 +137,4 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
return this.logoutHandlers;
}
BeanMetadataElement getLogoutSuccessHandler() {
return this.logoutSuccessHandler;
}
}
@@ -50,8 +50,6 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
private final BeanReference authenticationManager;
private final BeanReference authenticationFilterSecurityContextRepositoryRef;
private BeanDefinition defaultAuthorizedClientRepository;
private BeanDefinition authorizationRequestRedirectFilter;
@@ -60,11 +58,9 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
private BeanDefinition authorizationCodeAuthenticationProvider;
OAuth2ClientBeanDefinitionParser(BeanReference requestCache, BeanReference authenticationManager,
BeanReference authenticationFilterSecurityContextRepositoryRef) {
OAuth2ClientBeanDefinitionParser(BeanReference requestCache, BeanReference authenticationManager) {
this.requestCache = requestCache;
this.authenticationManager = authenticationManager;
this.authenticationFilterSecurityContextRepositoryRef = authenticationFilterSecurityContextRepositoryRef;
}
@Override
@@ -96,16 +92,11 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
this.authorizationRequestRedirectFilter = authorizationRequestRedirectFilterBuilder
.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository)
.addPropertyValue("requestCache", this.requestCache).getBeanDefinition();
BeanDefinitionBuilder authorizationCodeGrantFilterBldr = BeanDefinitionBuilder
this.authorizationCodeGrantFilter = BeanDefinitionBuilder
.rootBeanDefinition(OAuth2AuthorizationCodeGrantFilter.class)
.addConstructorArgValue(clientRegistrationRepository).addConstructorArgValue(authorizedClientRepository)
.addConstructorArgValue(this.authenticationManager)
.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository);
if (this.authenticationFilterSecurityContextRepositoryRef != null) {
authorizationCodeGrantFilterBldr.addPropertyValue("securityContextRepository",
this.authenticationFilterSecurityContextRepositoryRef);
}
this.authorizationCodeGrantFilter = authorizationCodeGrantFilterBldr.getBeanDefinition();
.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository).getBeanDefinition();
BeanMetadataElement accessTokenResponseClient = getAccessTokenResponseClient(authorizationCodeGrantElt);
this.authorizationCodeAuthenticationProvider = BeanDefinitionBuilder
@@ -1,323 +0,0 @@
/*
* Copyright 2002-2022 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.http;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.ResolvableType;
import org.springframework.security.config.Elements;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
* SAML 2.0 Login {@link BeanDefinitionParser}
*
* @author Marcus da Coregio
* @since 5.7
*/
final class Saml2LoginBeanDefinitionParser implements BeanDefinitionParser {
private static final String DEFAULT_LOGIN_URI = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
private static final String DEFAULT_AUTHENTICATION_REQUEST_PROCESSING_URL = "/saml2/authenticate/{registrationId}";
private static final String ATT_LOGIN_PROCESSING_URL = "login-processing-url";
private static final String ATT_LOGIN_PAGE = "login-page";
private static final String ELT_RELYING_PARTY_REGISTRATION = "relying-party-registration";
private static final String ELT_REGISTRATION_ID = "registration-id";
private static final String ATT_AUTHENTICATION_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
private static final String ATT_AUTHENTICATION_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
private static final String ATT_AUTHENTICATION_MANAGER_REF = "authentication-manager-ref";
private final List<BeanDefinition> csrfIgnoreRequestMatchers;
private final BeanReference portMapper;
private final BeanReference portResolver;
private final BeanReference requestCache;
private final boolean allowSessionCreation;
private final BeanReference authenticationManager;
private final BeanReference authenticationFilterSecurityContextRepositoryRef;
private final List<BeanReference> authenticationProviders;
private final Map<BeanDefinition, BeanMetadataElement> entryPoints;
private String loginProcessingUrl = Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
private BeanDefinition saml2WebSsoAuthenticationRequestFilter;
private BeanDefinition saml2AuthenticationUrlToProviderName;
Saml2LoginBeanDefinitionParser(List<BeanDefinition> csrfIgnoreRequestMatchers, BeanReference portMapper,
BeanReference portResolver, BeanReference requestCache, boolean allowSessionCreation,
BeanReference authenticationManager, BeanReference authenticationFilterSecurityContextRepositoryRef,
List<BeanReference> authenticationProviders, Map<BeanDefinition, BeanMetadataElement> entryPoints) {
this.csrfIgnoreRequestMatchers = csrfIgnoreRequestMatchers;
this.portMapper = portMapper;
this.portResolver = portResolver;
this.requestCache = requestCache;
this.allowSessionCreation = allowSessionCreation;
this.authenticationManager = authenticationManager;
this.authenticationFilterSecurityContextRepositoryRef = authenticationFilterSecurityContextRepositoryRef;
this.authenticationProviders = authenticationProviders;
this.entryPoints = entryPoints;
}
@Override
public BeanDefinition parse(Element element, ParserContext pc) {
String loginProcessingUrl = element.getAttribute(ATT_LOGIN_PROCESSING_URL);
if (StringUtils.hasText(loginProcessingUrl)) {
this.loginProcessingUrl = loginProcessingUrl;
}
BeanDefinition saml2LoginBeanConfig = BeanDefinitionBuilder.rootBeanDefinition(Saml2LoginBeanConfig.class)
.getBeanDefinition();
String saml2LoginBeanConfigId = pc.getReaderContext().generateBeanName(saml2LoginBeanConfig);
pc.registerBeanComponent(new BeanComponentDefinition(saml2LoginBeanConfig, saml2LoginBeanConfigId));
registerDefaultCsrfOverride();
BeanMetadataElement relyingPartyRegistrationRepository = Saml2LoginBeanDefinitionParserUtils
.getRelyingPartyRegistrationRepository(element);
BeanMetadataElement authenticationRequestRepository = Saml2LoginBeanDefinitionParserUtils
.getAuthenticationRequestRepository(element);
BeanMetadataElement authenticationRequestResolver = Saml2LoginBeanDefinitionParserUtils
.getAuthenticationRequestResolver(element);
if (authenticationRequestResolver == null) {
authenticationRequestResolver = Saml2LoginBeanDefinitionParserUtils
.createDefaultAuthenticationRequestResolver(relyingPartyRegistrationRepository);
}
BeanMetadataElement authenticationConverter = Saml2LoginBeanDefinitionParserUtils
.getAuthenticationConverter(element);
if (authenticationConverter == null) {
if (!this.loginProcessingUrl.contains("{registrationId}")) {
pc.getReaderContext().error("loginProcessingUrl must contain {registrationId} path variable", element);
}
authenticationConverter = Saml2LoginBeanDefinitionParserUtils
.createDefaultAuthenticationConverter(relyingPartyRegistrationRepository);
}
// Configure the Saml2WebSsoAuthenticationFilter
BeanDefinitionBuilder saml2WebSsoAuthenticationFilterBuilder = BeanDefinitionBuilder
.rootBeanDefinition(Saml2WebSsoAuthenticationFilter.class)
.addConstructorArgValue(authenticationConverter).addConstructorArgValue(this.loginProcessingUrl)
.addPropertyValue("authenticationRequestRepository", authenticationRequestRepository);
resolveLoginPage(element, pc);
resolveAuthenticationSuccessHandler(element, saml2WebSsoAuthenticationFilterBuilder);
resolveAuthenticationFailureHandler(element, saml2WebSsoAuthenticationFilterBuilder);
resolveAuthenticationManager(element, saml2WebSsoAuthenticationFilterBuilder);
resolveSecurityContextRepository(element, saml2WebSsoAuthenticationFilterBuilder);
// Configure the Saml2WebSsoAuthenticationRequestFilter
this.saml2WebSsoAuthenticationRequestFilter = BeanDefinitionBuilder
.rootBeanDefinition(Saml2WebSsoAuthenticationRequestFilter.class)
.addConstructorArgValue(authenticationRequestResolver)
.addPropertyValue("authenticationRequestRepository", authenticationRequestRepository)
.getBeanDefinition();
BeanDefinition saml2AuthenticationProvider = Saml2LoginBeanDefinitionParserUtils.createAuthenticationProvider();
this.authenticationProviders.add(
new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(saml2AuthenticationProvider)));
this.saml2AuthenticationUrlToProviderName = BeanDefinitionBuilder.rootBeanDefinition(Map.class)
.setFactoryMethodOnBean("getAuthenticationUrlToProviderName", saml2LoginBeanConfigId)
.getBeanDefinition();
return saml2WebSsoAuthenticationFilterBuilder.getBeanDefinition();
}
private void resolveAuthenticationManager(Element element,
BeanDefinitionBuilder saml2WebSsoAuthenticationFilterBuilder) {
String authenticationManagerRef = element.getAttribute(ATT_AUTHENTICATION_MANAGER_REF);
if (StringUtils.hasText(authenticationManagerRef)) {
saml2WebSsoAuthenticationFilterBuilder.addPropertyReference("authenticationManager",
authenticationManagerRef);
}
else {
saml2WebSsoAuthenticationFilterBuilder.addPropertyValue("authenticationManager",
this.authenticationManager);
}
}
private void resolveSecurityContextRepository(Element element,
BeanDefinitionBuilder saml2WebSsoAuthenticationFilterBuilder) {
if (this.authenticationFilterSecurityContextRepositoryRef != null) {
saml2WebSsoAuthenticationFilterBuilder.addPropertyValue("securityContextRepository",
this.authenticationFilterSecurityContextRepositoryRef);
}
}
private void resolveLoginPage(Element element, ParserContext parserContext) {
String loginPage = element.getAttribute(ATT_LOGIN_PAGE);
Object source = parserContext.extractSource(element);
BeanDefinition saml2LoginAuthenticationEntryPoint = null;
if (StringUtils.hasText(loginPage)) {
WebConfigUtils.validateHttpRedirect(loginPage, parserContext, source);
saml2LoginAuthenticationEntryPoint = BeanDefinitionBuilder
.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class).addConstructorArgValue(loginPage)
.addPropertyValue("portMapper", this.portMapper).addPropertyValue("portResolver", this.portResolver)
.getBeanDefinition();
}
else {
Map<String, String> identityProviderUrlMap = getIdentityProviderUrlMap(element);
if (identityProviderUrlMap.size() == 1) {
String loginUrl = identityProviderUrlMap.entrySet().iterator().next().getKey();
saml2LoginAuthenticationEntryPoint = BeanDefinitionBuilder
.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class).addConstructorArgValue(loginUrl)
.addPropertyValue("portMapper", this.portMapper)
.addPropertyValue("portResolver", this.portResolver).getBeanDefinition();
}
}
if (saml2LoginAuthenticationEntryPoint != null) {
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
.rootBeanDefinition(AntPathRequestMatcher.class);
requestMatcherBuilder.addConstructorArgValue(this.loginProcessingUrl);
BeanDefinition requestMatcher = requestMatcherBuilder.getBeanDefinition();
this.entryPoints.put(requestMatcher, saml2LoginAuthenticationEntryPoint);
}
}
private void resolveAuthenticationFailureHandler(Element element,
BeanDefinitionBuilder saml2WebSsoAuthenticationFilterBuilder) {
String authenticationFailureHandlerRef = element.getAttribute(ATT_AUTHENTICATION_FAILURE_HANDLER_REF);
if (StringUtils.hasText(authenticationFailureHandlerRef)) {
saml2WebSsoAuthenticationFilterBuilder.addPropertyReference("authenticationFailureHandler",
authenticationFailureHandlerRef);
}
else {
BeanDefinitionBuilder failureHandlerBuilder = BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler");
failureHandlerBuilder.addConstructorArgValue(
DEFAULT_LOGIN_URI + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME);
failureHandlerBuilder.addPropertyValue("allowSessionCreation", this.allowSessionCreation);
saml2WebSsoAuthenticationFilterBuilder.addPropertyValue("authenticationFailureHandler",
failureHandlerBuilder.getBeanDefinition());
}
}
private void resolveAuthenticationSuccessHandler(Element element,
BeanDefinitionBuilder saml2WebSsoAuthenticationFilterBuilder) {
String authenticationSuccessHandlerRef = element.getAttribute(ATT_AUTHENTICATION_SUCCESS_HANDLER_REF);
if (StringUtils.hasText(authenticationSuccessHandlerRef)) {
saml2WebSsoAuthenticationFilterBuilder.addPropertyReference("authenticationSuccessHandler",
authenticationSuccessHandlerRef);
}
else {
BeanDefinitionBuilder successHandlerBuilder = BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler")
.addPropertyValue("requestCache", this.requestCache);
saml2WebSsoAuthenticationFilterBuilder.addPropertyValue("authenticationSuccessHandler",
successHandlerBuilder.getBeanDefinition());
}
}
private void registerDefaultCsrfOverride() {
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
.rootBeanDefinition(AntPathRequestMatcher.class);
requestMatcherBuilder.addConstructorArgValue(this.loginProcessingUrl);
BeanDefinition requestMatcher = requestMatcherBuilder.getBeanDefinition();
this.csrfIgnoreRequestMatchers.add(requestMatcher);
}
private Map<String, String> getIdentityProviderUrlMap(Element element) {
Map<String, String> idps = new LinkedHashMap<>();
Element relyingPartyRegistrationsElt = DomUtils.getChildElementByTagName(
element.getOwnerDocument().getDocumentElement(), Elements.RELYING_PARTY_REGISTRATIONS);
String authenticationRequestProcessingUrl = DEFAULT_AUTHENTICATION_REQUEST_PROCESSING_URL;
if (relyingPartyRegistrationsElt != null) {
List<Element> relyingPartyRegList = DomUtils.getChildElementsByTagName(relyingPartyRegistrationsElt,
ELT_RELYING_PARTY_REGISTRATION);
for (Element relyingPartyReg : relyingPartyRegList) {
String registrationId = relyingPartyReg.getAttribute(ELT_REGISTRATION_ID);
idps.put(authenticationRequestProcessingUrl.replace("{registrationId}", registrationId),
registrationId);
}
}
return idps;
}
BeanDefinition getSaml2WebSsoAuthenticationRequestFilter() {
return this.saml2WebSsoAuthenticationRequestFilter;
}
BeanDefinition getSaml2AuthenticationUrlToProviderName() {
return this.saml2AuthenticationUrlToProviderName;
}
/**
* Wrapper bean class to provide configuration from applicationContext
*/
public static class Saml2LoginBeanConfig implements ApplicationContextAware {
private ApplicationContext context;
@SuppressWarnings({ "unchecked", "unused" })
Map<String, String> getAuthenticationUrlToProviderName() {
Iterable<RelyingPartyRegistration> relyingPartyRegistrations = null;
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository = this.context
.getBean(RelyingPartyRegistrationRepository.class);
ResolvableType type = ResolvableType.forInstance(relyingPartyRegistrationRepository).as(Iterable.class);
if (type != ResolvableType.NONE
&& RelyingPartyRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) {
relyingPartyRegistrations = (Iterable<RelyingPartyRegistration>) relyingPartyRegistrationRepository;
}
if (relyingPartyRegistrations == null) {
return Collections.emptyMap();
}
String authenticationRequestProcessingUrl = DEFAULT_AUTHENTICATION_REQUEST_PROCESSING_URL;
Map<String, String> saml2AuthenticationUrlToProviderName = new HashMap<>();
relyingPartyRegistrations.forEach((registration) -> saml2AuthenticationUrlToProviderName.put(
authenticationRequestProcessingUrl.replace("{registrationId}", registration.getRegistrationId()),
registration.getRegistrationId()));
return saml2AuthenticationUrlToProviderName;
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
}
}
@@ -1,107 +0,0 @@
/*
* Copyright 2002-2022 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.http;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
import org.springframework.util.StringUtils;
/**
* @author Marcus da Coregio
* @since 5.7
*/
final class Saml2LoginBeanDefinitionParserUtils {
private static final String ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF = "relying-party-registration-repository-ref";
private static final String ATT_AUTHENTICATION_REQUEST_REPOSITORY_REF = "authentication-request-repository-ref";
private static final String ATT_AUTHENTICATION_REQUEST_RESOLVER_REF = "authentication-request-resolver-ref";
private static final String ATT_AUTHENTICATION_CONVERTER = "authentication-converter-ref";
private Saml2LoginBeanDefinitionParserUtils() {
}
static BeanMetadataElement getRelyingPartyRegistrationRepository(Element element) {
String relyingPartyRegistrationRepositoryRef = element
.getAttribute(ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF);
if (StringUtils.hasText(relyingPartyRegistrationRepositoryRef)) {
return new RuntimeBeanReference(relyingPartyRegistrationRepositoryRef);
}
return new RuntimeBeanReference(RelyingPartyRegistrationRepository.class);
}
static BeanMetadataElement getAuthenticationRequestRepository(Element element) {
String authenticationRequestRepositoryRef = element.getAttribute(ATT_AUTHENTICATION_REQUEST_REPOSITORY_REF);
if (StringUtils.hasText(authenticationRequestRepositoryRef)) {
return new RuntimeBeanReference(authenticationRequestRepositoryRef);
}
return BeanDefinitionBuilder.rootBeanDefinition(HttpSessionSaml2AuthenticationRequestRepository.class)
.getBeanDefinition();
}
static BeanMetadataElement getAuthenticationRequestResolver(Element element) {
String authenticationRequestContextResolver = element.getAttribute(ATT_AUTHENTICATION_REQUEST_RESOLVER_REF);
if (StringUtils.hasText(authenticationRequestContextResolver)) {
return new RuntimeBeanReference(authenticationRequestContextResolver);
}
return null;
}
static BeanMetadataElement createDefaultAuthenticationRequestResolver(
BeanMetadataElement relyingPartyRegistrationRepository) {
BeanMetadataElement defaultRelyingPartyRegistrationResolver = BeanDefinitionBuilder
.rootBeanDefinition(DefaultRelyingPartyRegistrationResolver.class)
.addConstructorArgValue(relyingPartyRegistrationRepository).getBeanDefinition();
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver")
.addConstructorArgValue(defaultRelyingPartyRegistrationResolver).getBeanDefinition();
}
static BeanDefinition createAuthenticationProvider() {
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider")
.getBeanDefinition();
}
static BeanMetadataElement getAuthenticationConverter(Element element) {
String authenticationConverter = element.getAttribute(ATT_AUTHENTICATION_CONVERTER);
if (StringUtils.hasText(authenticationConverter)) {
return new RuntimeBeanReference(authenticationConverter);
}
return null;
}
static BeanDefinition createDefaultAuthenticationConverter(BeanMetadataElement relyingPartyRegistrationRepository) {
AbstractBeanDefinition resolver = BeanDefinitionBuilder
.rootBeanDefinition(DefaultRelyingPartyRegistrationResolver.class)
.addConstructorArgValue(relyingPartyRegistrationRepository).getBeanDefinition();
return BeanDefinitionBuilder.rootBeanDefinition(Saml2AuthenticationTokenConverter.class)
.addConstructorArgValue(resolver).getBeanDefinition();
}
}
@@ -1,236 +0,0 @@
/*
* Copyright 2002-2022 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.http;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import javax.servlet.http.HttpServletRequest;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter;
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2RelyingPartyInitiatedLogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessEventPublishingLogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* SAML 2.0 Single Logout {@link BeanDefinitionParser}
*
* @author Marcus da Coregio
* @since 5.7
*/
final class Saml2LogoutBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_LOGOUT_REQUEST_URL = "logout-request-url";
private static final String ATT_LOGOUT_RESPONSE_URL = "logout-response-url";
private static final String ATT_LOGOUT_URL = "logout-url";
private List<BeanMetadataElement> logoutHandlers;
private String logoutUrl = "/logout";
private String logoutRequestUrl = "/logout/saml2/slo";
private String logoutResponseUrl = "/logout/saml2/slo";
private BeanMetadataElement logoutSuccessHandler;
private BeanDefinition logoutRequestFilter;
private BeanDefinition logoutResponseFilter;
private BeanDefinition logoutFilter;
Saml2LogoutBeanDefinitionParser(ManagedList<BeanMetadataElement> logoutHandlers,
BeanMetadataElement logoutSuccessHandler) {
this.logoutHandlers = logoutHandlers;
this.logoutSuccessHandler = logoutSuccessHandler;
}
@Override
public BeanDefinition parse(Element element, ParserContext pc) {
String logoutUrl = element.getAttribute(ATT_LOGOUT_URL);
if (StringUtils.hasText(logoutUrl)) {
this.logoutUrl = logoutUrl;
}
String logoutRequestUrl = element.getAttribute(ATT_LOGOUT_REQUEST_URL);
if (StringUtils.hasText(logoutRequestUrl)) {
this.logoutRequestUrl = logoutRequestUrl;
}
String logoutResponseUrl = element.getAttribute(ATT_LOGOUT_RESPONSE_URL);
if (StringUtils.hasText(logoutResponseUrl)) {
this.logoutResponseUrl = logoutResponseUrl;
}
WebConfigUtils.validateHttpRedirect(this.logoutUrl, pc, element);
WebConfigUtils.validateHttpRedirect(this.logoutRequestUrl, pc, element);
WebConfigUtils.validateHttpRedirect(this.logoutResponseUrl, pc, element);
if (CollectionUtils.isEmpty(this.logoutHandlers)) {
this.logoutHandlers = createDefaultLogoutHandlers();
}
if (this.logoutSuccessHandler == null) {
this.logoutSuccessHandler = createDefaultLogoutSuccessHandler();
}
BeanMetadataElement relyingPartyRegistrationRepository = Saml2LogoutBeanDefinitionParserUtils
.getRelyingPartyRegistrationRepository(element);
BeanMetadataElement registrations = BeanDefinitionBuilder
.rootBeanDefinition(DefaultRelyingPartyRegistrationResolver.class)
.addConstructorArgValue(relyingPartyRegistrationRepository).getBeanDefinition();
BeanMetadataElement logoutResponseResolver = Saml2LogoutBeanDefinitionParserUtils
.getLogoutResponseResolver(element, registrations);
BeanMetadataElement logoutRequestValidator = Saml2LogoutBeanDefinitionParserUtils
.getLogoutRequestValidator(element);
BeanMetadataElement logoutRequestMatcher = createSaml2LogoutRequestMatcher();
this.logoutRequestFilter = BeanDefinitionBuilder.rootBeanDefinition(Saml2LogoutRequestFilter.class)
.addConstructorArgValue(registrations).addConstructorArgValue(logoutRequestValidator)
.addConstructorArgValue(logoutResponseResolver).addConstructorArgValue(this.logoutHandlers)
.addPropertyValue("logoutRequestMatcher", logoutRequestMatcher).getBeanDefinition();
BeanMetadataElement logoutResponseValidator = Saml2LogoutBeanDefinitionParserUtils
.getLogoutResponseValidator(element);
BeanMetadataElement logoutRequestRepository = Saml2LogoutBeanDefinitionParserUtils
.getLogoutRequestRepository(element);
BeanMetadataElement logoutResponseMatcher = createSaml2LogoutResponseMatcher();
this.logoutResponseFilter = BeanDefinitionBuilder.rootBeanDefinition(Saml2LogoutResponseFilter.class)
.addConstructorArgValue(registrations).addConstructorArgValue(logoutResponseValidator)
.addConstructorArgValue(this.logoutSuccessHandler)
.addPropertyValue("logoutRequestMatcher", logoutResponseMatcher)
.addPropertyValue("logoutRequestRepository", logoutRequestRepository).getBeanDefinition();
BeanMetadataElement logoutRequestResolver = Saml2LogoutBeanDefinitionParserUtils
.getLogoutRequestResolver(element, registrations);
BeanMetadataElement saml2LogoutRequestSuccessHandler = BeanDefinitionBuilder
.rootBeanDefinition(Saml2RelyingPartyInitiatedLogoutSuccessHandler.class)
.addConstructorArgValue(logoutRequestResolver).getBeanDefinition();
this.logoutFilter = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class)
.addConstructorArgValue(saml2LogoutRequestSuccessHandler).addConstructorArgValue(this.logoutHandlers)
.addPropertyValue("logoutRequestMatcher", createLogoutRequestMatcher()).getBeanDefinition();
return null;
}
private static List<BeanMetadataElement> createDefaultLogoutHandlers() {
List<BeanMetadataElement> handlers = new ManagedList<>();
handlers.add(BeanDefinitionBuilder.rootBeanDefinition(SecurityContextLogoutHandler.class).getBeanDefinition());
handlers.add(BeanDefinitionBuilder.rootBeanDefinition(LogoutSuccessEventPublishingLogoutHandler.class)
.getBeanDefinition());
return handlers;
}
private static BeanMetadataElement createDefaultLogoutSuccessHandler() {
return BeanDefinitionBuilder.rootBeanDefinition(SimpleUrlLogoutSuccessHandler.class)
.addPropertyValue("defaultTargetUrl", "/login?logout").getBeanDefinition();
}
private BeanMetadataElement createLogoutRequestMatcher() {
BeanMetadataElement logoutMatcher = BeanDefinitionBuilder.rootBeanDefinition(AntPathRequestMatcher.class)
.addConstructorArgValue(this.logoutUrl).addConstructorArgValue("POST").getBeanDefinition();
BeanMetadataElement saml2Matcher = BeanDefinitionBuilder.rootBeanDefinition(Saml2RequestMatcher.class)
.getBeanDefinition();
return BeanDefinitionBuilder.rootBeanDefinition(AndRequestMatcher.class)
.addConstructorArgValue(toManagedList(logoutMatcher, saml2Matcher)).getBeanDefinition();
}
private BeanMetadataElement createSaml2LogoutRequestMatcher() {
BeanMetadataElement logoutRequestMatcher = BeanDefinitionBuilder.rootBeanDefinition(AntPathRequestMatcher.class)
.addConstructorArgValue(this.logoutRequestUrl).getBeanDefinition();
BeanMetadataElement saml2RequestMatcher = BeanDefinitionBuilder
.rootBeanDefinition(ParameterRequestMatcher.class).addConstructorArgValue("SAMLRequest")
.getBeanDefinition();
return BeanDefinitionBuilder.rootBeanDefinition(AndRequestMatcher.class)
.addConstructorArgValue(toManagedList(logoutRequestMatcher, saml2RequestMatcher)).getBeanDefinition();
}
private BeanMetadataElement createSaml2LogoutResponseMatcher() {
BeanMetadataElement logoutResponseMatcher = BeanDefinitionBuilder
.rootBeanDefinition(AntPathRequestMatcher.class).addConstructorArgValue(this.logoutResponseUrl)
.getBeanDefinition();
BeanMetadataElement saml2ResponseMatcher = BeanDefinitionBuilder
.rootBeanDefinition(ParameterRequestMatcher.class).addConstructorArgValue("SAMLResponse")
.getBeanDefinition();
return BeanDefinitionBuilder.rootBeanDefinition(AndRequestMatcher.class)
.addConstructorArgValue(toManagedList(logoutResponseMatcher, saml2ResponseMatcher)).getBeanDefinition();
}
private static List<BeanMetadataElement> toManagedList(BeanMetadataElement... elements) {
List<BeanMetadataElement> managedList = new ManagedList<>();
managedList.addAll(Arrays.asList(elements));
return managedList;
}
BeanDefinition getLogoutRequestFilter() {
return this.logoutRequestFilter;
}
BeanDefinition getLogoutResponseFilter() {
return this.logoutResponseFilter;
}
BeanDefinition getLogoutFilter() {
return this.logoutFilter;
}
private static class ParameterRequestMatcher implements RequestMatcher {
Predicate<String> test = Objects::nonNull;
String name;
ParameterRequestMatcher(String name) {
this.name = name;
}
@Override
public boolean matches(HttpServletRequest request) {
return this.test.test(request.getParameter(this.name));
}
}
private static class Saml2RequestMatcher implements RequestMatcher {
@Override
public boolean matches(HttpServletRequest request) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return false;
}
return authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal;
}
}
}
@@ -1,104 +0,0 @@
/*
* Copyright 2002-2022 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.http;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlLogoutRequestValidator;
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlLogoutResponseValidator;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository;
import org.springframework.util.StringUtils;
/**
* @author Marcus da Coregio
* @since 5.7
*/
final class Saml2LogoutBeanDefinitionParserUtils {
private static final String ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF = "relying-party-registration-repository-ref";
private static final String ATT_LOGOUT_REQUEST_VALIDATOR_REF = "logout-request-validator-ref";
private static final String ATT_LOGOUT_REQUEST_REPOSITORY_REF = "logout-request-repository-ref";
private static final String ATT_LOGOUT_REQUEST_RESOLVER_REF = "logout-request-resolver-ref";
private static final String ATT_LOGOUT_RESPONSE_RESOLVER_REF = "logout-response-resolver-ref";
private static final String ATT_LOGOUT_RESPONSE_VALIDATOR_REF = "logout-response-validator-ref";
private Saml2LogoutBeanDefinitionParserUtils() {
}
static BeanMetadataElement getRelyingPartyRegistrationRepository(Element element) {
String relyingPartyRegistrationRepositoryRef = element
.getAttribute(ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF);
if (StringUtils.hasText(relyingPartyRegistrationRepositoryRef)) {
return new RuntimeBeanReference(relyingPartyRegistrationRepositoryRef);
}
return new RuntimeBeanReference(RelyingPartyRegistrationRepository.class);
}
static BeanMetadataElement getLogoutResponseResolver(Element element, BeanMetadataElement registrations) {
String logoutResponseResolver = element.getAttribute(ATT_LOGOUT_RESPONSE_RESOLVER_REF);
if (StringUtils.hasText(logoutResponseResolver)) {
return new RuntimeBeanReference(logoutResponseResolver);
}
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver")
.addConstructorArgValue(registrations).getBeanDefinition();
}
static BeanMetadataElement getLogoutRequestValidator(Element element) {
String logoutRequestValidator = element.getAttribute(ATT_LOGOUT_REQUEST_VALIDATOR_REF);
if (StringUtils.hasText(logoutRequestValidator)) {
return new RuntimeBeanReference(logoutRequestValidator);
}
return BeanDefinitionBuilder.rootBeanDefinition(OpenSamlLogoutRequestValidator.class).getBeanDefinition();
}
static BeanMetadataElement getLogoutResponseValidator(Element element) {
String logoutResponseValidator = element.getAttribute(ATT_LOGOUT_RESPONSE_VALIDATOR_REF);
if (StringUtils.hasText(logoutResponseValidator)) {
return new RuntimeBeanReference(logoutResponseValidator);
}
return BeanDefinitionBuilder.rootBeanDefinition(OpenSamlLogoutResponseValidator.class).getBeanDefinition();
}
static BeanMetadataElement getLogoutRequestRepository(Element element) {
String logoutRequestRepository = element.getAttribute(ATT_LOGOUT_REQUEST_REPOSITORY_REF);
if (StringUtils.hasText(logoutRequestRepository)) {
return new RuntimeBeanReference(logoutRequestRepository);
}
return BeanDefinitionBuilder.rootBeanDefinition(HttpSessionLogoutRequestRepository.class).getBeanDefinition();
}
static BeanMetadataElement getLogoutRequestResolver(Element element, BeanMetadataElement registrations) {
String logoutRequestResolver = element.getAttribute(ATT_LOGOUT_REQUEST_RESOLVER_REF);
if (StringUtils.hasText(logoutRequestResolver)) {
return new RuntimeBeanReference(logoutRequestResolver);
}
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutRequestResolver")
.addConstructorArgValue(registrations).getBeanDefinition();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -29,10 +29,6 @@ enum SecurityFilters {
FIRST(Integer.MIN_VALUE),
DISABLE_ENCODE_URL_FILTER,
FORCE_EAGER_SESSION_FILTER,
CHANNEL_FILTER,
SECURITY_CONTEXT_FILTER,
@@ -45,20 +41,12 @@ enum SecurityFilters {
CORS_FILTER,
SAML2_LOGOUT_REQUEST_FILTER,
SAML2_LOGOUT_RESPONSE_FILTER,
CSRF_FILTER,
SAML2_LOGOUT_FILTER,
LOGOUT_FILTER,
OAUTH2_AUTHORIZATION_REQUEST_FILTER,
SAML2_AUTHENTICATION_REQUEST_FILTER,
X509_FILTER,
PRE_AUTH_FILTER,
@@ -67,8 +55,6 @@ enum SecurityFilters {
OAUTH2_LOGIN_FILTER,
SAML2_AUTHENTICATION_FILTER,
FORM_LOGIN_FILTER,
OPENID_FILTER,
@@ -1,183 +0,0 @@
/*
* Copyright 2002-2022 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.ldap;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.ldap.authentication.AbstractLdapAuthenticator;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
/**
* Creates an {@link AuthenticationManager} that can perform LDAP authentication.
*
* @author Eleftheria Stein
* @since 5.7
*/
public abstract class AbstractLdapAuthenticationManagerFactory<T extends AbstractLdapAuthenticator> {
AbstractLdapAuthenticationManagerFactory(BaseLdapPathContextSource contextSource) {
this.contextSource = contextSource;
}
private BaseLdapPathContextSource contextSource;
private String[] userDnPatterns;
private LdapAuthoritiesPopulator ldapAuthoritiesPopulator;
private GrantedAuthoritiesMapper authoritiesMapper;
private UserDetailsContextMapper userDetailsContextMapper;
private String userSearchFilter;
private String userSearchBase = "";
/**
* Sets the {@link BaseLdapPathContextSource} used to perform LDAP authentication.
* @param contextSource the {@link BaseLdapPathContextSource} used to perform LDAP
* authentication
*/
public void setContextSource(BaseLdapPathContextSource contextSource) {
this.contextSource = contextSource;
}
/**
* Gets the {@link BaseLdapPathContextSource} used to perform LDAP authentication.
* @return the {@link BaseLdapPathContextSource} used to perform LDAP authentication
*/
protected final BaseLdapPathContextSource getContextSource() {
return this.contextSource;
}
/**
* Sets the {@link LdapAuthoritiesPopulator} used to obtain a list of granted
* authorities for an LDAP user.
* @param ldapAuthoritiesPopulator the {@link LdapAuthoritiesPopulator} to use
*/
public void setLdapAuthoritiesPopulator(LdapAuthoritiesPopulator ldapAuthoritiesPopulator) {
this.ldapAuthoritiesPopulator = ldapAuthoritiesPopulator;
}
/**
* Sets the {@link GrantedAuthoritiesMapper} used for converting the authorities
* loaded from storage to a new set of authorities which will be associated to the
* {@link UsernamePasswordAuthenticationToken}.
* @param authoritiesMapper the {@link GrantedAuthoritiesMapper} used for mapping the
* user's authorities
*/
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
this.authoritiesMapper = authoritiesMapper;
}
/**
* Sets a custom strategy to be used for creating the {@link UserDetails} which will
* be stored as the principal in the {@link Authentication}.
* @param userDetailsContextMapper the strategy instance
*/
public void setUserDetailsContextMapper(UserDetailsContextMapper userDetailsContextMapper) {
this.userDetailsContextMapper = userDetailsContextMapper;
}
/**
* If your users are at a fixed location in the directory (i.e. you can work out the
* DN directly from the username without doing a directory search), you can use this
* attribute to map directly to the DN. It maps directly to the userDnPatterns
* property of AbstractLdapAuthenticator. The value is a specific pattern used to
* build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present
* and will be substituted with the username.
* @param userDnPatterns the LDAP patterns for finding the usernames
*/
public void setUserDnPatterns(String... userDnPatterns) {
this.userDnPatterns = userDnPatterns;
}
/**
* The LDAP filter used to search for users (optional). For example "(uid={0})". The
* substituted parameter is the user's login name.
* @param userSearchFilter the LDAP filter used to search for users
*/
public void setUserSearchFilter(String userSearchFilter) {
this.userSearchFilter = userSearchFilter;
}
/**
* Search base for user searches. Defaults to "". Only used with
* {@link #setUserSearchFilter(String)}.
* @param userSearchBase search base for user searches
*/
public void setUserSearchBase(String userSearchBase) {
this.userSearchBase = userSearchBase;
}
/**
* Returns the configured {@link AuthenticationManager} that can be used to perform
* LDAP authentication.
* @return the configured {@link AuthenticationManager}
*/
public final AuthenticationManager createAuthenticationManager() {
LdapAuthenticationProvider ldapAuthenticationProvider = getProvider();
return new ProviderManager(ldapAuthenticationProvider);
}
private LdapAuthenticationProvider getProvider() {
AbstractLdapAuthenticator authenticator = getAuthenticator();
LdapAuthenticationProvider provider;
if (this.ldapAuthoritiesPopulator != null) {
provider = new LdapAuthenticationProvider(authenticator, this.ldapAuthoritiesPopulator);
}
else {
provider = new LdapAuthenticationProvider(authenticator);
}
if (this.authoritiesMapper != null) {
provider.setAuthoritiesMapper(this.authoritiesMapper);
}
if (this.userDetailsContextMapper != null) {
provider.setUserDetailsContextMapper(this.userDetailsContextMapper);
}
return provider;
}
private AbstractLdapAuthenticator getAuthenticator() {
AbstractLdapAuthenticator authenticator = createDefaultLdapAuthenticator();
if (this.userSearchFilter != null) {
authenticator.setUserSearch(
new FilterBasedLdapUserSearch(this.userSearchBase, this.userSearchFilter, this.contextSource));
}
if (this.userDnPatterns != null && this.userDnPatterns.length > 0) {
authenticator.setUserDnPatterns(this.userDnPatterns);
}
authenticator.afterPropertiesSet();
return authenticator;
}
/**
* Allows subclasses to supply the default {@link AbstractLdapAuthenticator}.
* @return the {@link AbstractLdapAuthenticator} that will be configured for LDAP
* authentication
*/
protected abstract T createDefaultLdapAuthenticator();
}
@@ -1,185 +0,0 @@
/*
* Copyright 2002-2022 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.ldap;
import java.io.IOException;
import java.net.ServerSocket;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.Lifecycle;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.server.EmbeddedLdapServerContainer;
import org.springframework.security.ldap.server.UnboundIdContainer;
import org.springframework.util.ClassUtils;
/**
* Creates a {@link DefaultSpringSecurityContextSource} used to perform LDAP
* authentication and starts and in-memory LDAP server.
*
* @author Eleftheria Stein
* @since 5.7
*/
public class EmbeddedLdapServerContextSourceFactoryBean
implements FactoryBean<DefaultSpringSecurityContextSource>, DisposableBean, ApplicationContextAware {
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
private static final int DEFAULT_PORT = 33389;
private static final int RANDOM_PORT = 0;
private Integer port;
private String ldif = "classpath*:*.ldif";
private String root = "dc=springframework,dc=org";
private ApplicationContext context;
private String managerDn;
private String managerPassword;
private EmbeddedLdapServerContainer container;
/**
* Create an EmbeddedLdapServerContextSourceFactoryBean that will use an embedded LDAP
* server to perform LDAP authentication. This requires a dependency on
* `com.unboundid:unboundid-ldapsdk`.
* @return the EmbeddedLdapServerContextSourceFactoryBean
*/
public static EmbeddedLdapServerContextSourceFactoryBean fromEmbeddedLdapServer() {
return new EmbeddedLdapServerContextSourceFactoryBean();
}
/**
* Specifies an LDIF to load at startup for an embedded LDAP server. The default is
* "classpath*:*.ldif".
* @param ldif the ldif to load at startup for an embedded LDAP server.
*/
public void setLdif(String ldif) {
this.ldif = ldif;
}
/**
* The port to connect to LDAP to (the default is 33389 or random available port if
* unavailable). Supplying 0 as the port indicates that a random available port should
* be selected.
* @param port the port to connect to
*/
public void setPort(int port) {
this.port = port;
}
/**
* Optional root suffix for the embedded LDAP server. Default is
* "dc=springframework,dc=org".
* @param root root suffix for the embedded LDAP server
*/
public void setRoot(String root) {
this.root = root;
}
/**
* Username (DN) of the "manager" user identity (i.e. "uid=admin,ou=system") which
* will be used to authenticate to an LDAP server. If omitted, anonymous access will
* be used.
* @param managerDn the username (DN) of the "manager" user identity used to
* authenticate to a LDAP server.
*/
public void setManagerDn(String managerDn) {
this.managerDn = managerDn;
}
/**
* The password for the manager DN. This is required if the
* {@link #setManagerDn(String)} is specified.
* @param managerPassword password for the manager DN
*/
public void setManagerPassword(String managerPassword) {
this.managerPassword = managerPassword;
}
@Override
public DefaultSpringSecurityContextSource getObject() throws Exception {
if (!ClassUtils.isPresent(UNBOUNDID_CLASSNAME, getClass().getClassLoader())) {
throw new IllegalStateException("Embedded LDAP server is not provided");
}
this.container = getContainer();
this.port = this.container.getPort();
DefaultSpringSecurityContextSource contextSourceFromProviderUrl = new DefaultSpringSecurityContextSource(
"ldap://127.0.0.1:" + this.port + "/" + this.root);
if (this.managerDn != null) {
contextSourceFromProviderUrl.setUserDn(this.managerDn);
if (this.managerPassword == null) {
throw new IllegalStateException("managerPassword is required if managerDn is supplied");
}
contextSourceFromProviderUrl.setPassword(this.managerPassword);
}
contextSourceFromProviderUrl.afterPropertiesSet();
return contextSourceFromProviderUrl;
}
@Override
public Class<?> getObjectType() {
return DefaultSpringSecurityContextSource.class;
}
@Override
public void destroy() {
if (this.container instanceof Lifecycle) {
((Lifecycle) this.container).stop();
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
private EmbeddedLdapServerContainer getContainer() {
if (!ClassUtils.isPresent(UNBOUNDID_CLASSNAME, getClass().getClassLoader())) {
throw new IllegalStateException("Embedded LDAP server is not provided");
}
UnboundIdContainer unboundIdContainer = new UnboundIdContainer(this.root, this.ldif);
unboundIdContainer.setApplicationContext(this.context);
unboundIdContainer.setPort(getEmbeddedServerPort());
unboundIdContainer.afterPropertiesSet();
return unboundIdContainer;
}
private int getEmbeddedServerPort() {
if (this.port == null) {
this.port = getDefaultEmbeddedServerPort();
}
return this.port;
}
private int getDefaultEmbeddedServerPort() {
try (ServerSocket serverSocket = new ServerSocket(DEFAULT_PORT)) {
return serverSocket.getLocalPort();
}
catch (IOException ex) {
return RANDOM_PORT;
}
}
}
@@ -1,41 +0,0 @@
/*
* Copyright 2002-2022 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.ldap;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.ldap.authentication.BindAuthenticator;
/**
* Creates an {@link AuthenticationManager} that can perform LDAP authentication using
* bind authentication.
*
* @author Eleftheria Stein
* @since 5.7
*/
public class LdapBindAuthenticationManagerFactory extends AbstractLdapAuthenticationManagerFactory<BindAuthenticator> {
public LdapBindAuthenticationManagerFactory(BaseLdapPathContextSource contextSource) {
super(contextSource);
}
@Override
protected BindAuthenticator createDefaultLdapAuthenticator() {
return new BindAuthenticator(getContextSource());
}
}
@@ -1,75 +0,0 @@
/*
* Copyright 2002-2022 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.ldap;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
import org.springframework.util.Assert;
/**
* Creates an {@link AuthenticationManager} that can perform LDAP authentication using
* password comparison.
*
* @author Eleftheria Stein
* @since 5.7
*/
public class LdapPasswordComparisonAuthenticationManagerFactory
extends AbstractLdapAuthenticationManagerFactory<PasswordComparisonAuthenticator> {
private PasswordEncoder passwordEncoder;
private String passwordAttribute;
public LdapPasswordComparisonAuthenticationManagerFactory(BaseLdapPathContextSource contextSource,
PasswordEncoder passwordEncoder) {
super(contextSource);
setPasswordEncoder(passwordEncoder);
}
/**
* Specifies the {@link PasswordEncoder} to be used when authenticating with password
* comparison.
* @param passwordEncoder the {@link PasswordEncoder} to use
*/
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
Assert.notNull(passwordEncoder, "passwordEncoder must not be null.");
this.passwordEncoder = passwordEncoder;
}
/**
* The attribute in the directory which contains the user password. Only used when
* authenticating with password comparison. Defaults to "userPassword".
* @param passwordAttribute the attribute in the directory which contains the user
* password
*/
public void setPasswordAttribute(String passwordAttribute) {
this.passwordAttribute = passwordAttribute;
}
@Override
protected PasswordComparisonAuthenticator createDefaultLdapAuthenticator() {
PasswordComparisonAuthenticator ldapAuthenticator = new PasswordComparisonAuthenticator(getContextSource());
if (this.passwordAttribute != null) {
ldapAuthenticator.setPasswordAttributeName(this.passwordAttribute);
}
ldapAuthenticator.setPasswordEncoder(this.passwordEncoder);
return ldapAuthenticator;
}
}
@@ -1,376 +0,0 @@
/*
* Copyright 2002-2022 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.saml2;
import java.io.InputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.security.converter.RsaKeyConverters;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
* @author Marcus da Coregio
* @since 5.7
*/
public final class RelyingPartyRegistrationsBeanDefinitionParser implements BeanDefinitionParser {
private static final String ELT_RELYING_PARTY_REGISTRATION = "relying-party-registration";
private static final String ELT_SIGNING_CREDENTIAL = "signing-credential";
private static final String ELT_DECRYPTION_CREDENTIAL = "decryption-credential";
private static final String ELT_ASSERTING_PARTY = "asserting-party";
private static final String ELT_VERIFICATION_CREDENTIAL = "verification-credential";
private static final String ELT_ENCRYPTION_CREDENTIAL = "encryption-credential";
private static final String ATT_REGISTRATION_ID = "registration-id";
private static final String ATT_ASSERTING_PARTY_ID = "asserting-party-id";
private static final String ATT_ENTITY_ID = "entity-id";
private static final String ATT_METADATA_LOCATION = "metadata-location";
private static final String ATT_ASSERTION_CONSUMER_SERVICE_LOCATION = "assertion-consumer-service-location";
private static final String ATT_ASSERTION_CONSUMER_SERVICE_BINDING = "assertion-consumer-service-binding";
private static final String ATT_PRIVATE_KEY_LOCATION = "private-key-location";
private static final String ATT_CERTIFICATE_LOCATION = "certificate-location";
private static final String ATT_WANT_AUTHN_REQUESTS_SIGNED = "want-authn-requests-signed";
private static final String ATT_SINGLE_SIGN_ON_SERVICE_LOCATION = "single-sign-on-service-location";
private static final String ATT_SINGLE_SIGN_ON_SERVICE_BINDING = "single-sign-on-service-binding";
private static final String ATT_SIGNING_ALGORITHMS = "signing-algorithms";
private static final String ATT_SINGLE_LOGOUT_SERVICE_LOCATION = "single-logout-service-location";
private static final String ATT_SINGLE_LOGOUT_SERVICE_RESPONSE_LOCATION = "single-logout-service-response-location";
private static final String ATT_SINGLE_LOGOUT_SERVICE_BINDING = "single-logout-service-binding";
private static final ResourceLoader resourceLoader = new DefaultResourceLoader();
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
Map<String, Map<String, Object>> assertingParties = getAssertingParties(element);
List<RelyingPartyRegistration> relyingPartyRegistrations = getRelyingPartyRegistrations(element,
assertingParties, parserContext);
BeanDefinition relyingPartyRegistrationRepositoryBean = BeanDefinitionBuilder
.rootBeanDefinition(InMemoryRelyingPartyRegistrationRepository.class)
.addConstructorArgValue(relyingPartyRegistrations).getBeanDefinition();
String relyingPartyRegistrationRepositoryId = parserContext.getReaderContext()
.generateBeanName(relyingPartyRegistrationRepositoryBean);
parserContext.registerBeanComponent(new BeanComponentDefinition(relyingPartyRegistrationRepositoryBean,
relyingPartyRegistrationRepositoryId));
parserContext.popAndRegisterContainingComponent();
return null;
}
private static Map<String, Map<String, Object>> getAssertingParties(Element element) {
List<Element> assertingPartyElts = DomUtils.getChildElementsByTagName(element, ELT_ASSERTING_PARTY);
Map<String, Map<String, Object>> providers = new HashMap<>();
for (Element assertingPartyElt : assertingPartyElts) {
Map<String, Object> assertingParty = new HashMap<>();
String assertingPartyId = assertingPartyElt.getAttribute(ATT_ASSERTING_PARTY_ID);
String entityId = assertingPartyElt.getAttribute(ATT_ENTITY_ID);
String wantAuthnRequestsSigned = assertingPartyElt.getAttribute(ATT_WANT_AUTHN_REQUESTS_SIGNED);
String singleSignOnServiceLocation = assertingPartyElt.getAttribute(ATT_SINGLE_SIGN_ON_SERVICE_LOCATION);
String singleSignOnServiceBinding = assertingPartyElt.getAttribute(ATT_SINGLE_SIGN_ON_SERVICE_BINDING);
String signingAlgorithms = assertingPartyElt.getAttribute(ATT_SIGNING_ALGORITHMS);
String singleLogoutServiceLocation = assertingPartyElt.getAttribute(ATT_SINGLE_LOGOUT_SERVICE_LOCATION);
String singleLogoutServiceResponseLocation = assertingPartyElt
.getAttribute(ATT_SINGLE_LOGOUT_SERVICE_RESPONSE_LOCATION);
String singleLogoutServiceBinding = assertingPartyElt.getAttribute(ATT_SINGLE_LOGOUT_SERVICE_BINDING);
assertingParty.put(ATT_ASSERTING_PARTY_ID, assertingPartyId);
assertingParty.put(ATT_ENTITY_ID, entityId);
assertingParty.put(ATT_WANT_AUTHN_REQUESTS_SIGNED, wantAuthnRequestsSigned);
assertingParty.put(ATT_SINGLE_SIGN_ON_SERVICE_LOCATION, singleSignOnServiceLocation);
assertingParty.put(ATT_SINGLE_SIGN_ON_SERVICE_BINDING, singleSignOnServiceBinding);
assertingParty.put(ATT_SIGNING_ALGORITHMS, signingAlgorithms);
assertingParty.put(ATT_SINGLE_LOGOUT_SERVICE_LOCATION, singleLogoutServiceLocation);
assertingParty.put(ATT_SINGLE_LOGOUT_SERVICE_RESPONSE_LOCATION, singleLogoutServiceResponseLocation);
assertingParty.put(ATT_SINGLE_LOGOUT_SERVICE_BINDING, singleLogoutServiceBinding);
addVerificationCredentials(assertingPartyElt, assertingParty);
addEncryptionCredentials(assertingPartyElt, assertingParty);
providers.put(assertingPartyId, assertingParty);
}
return providers;
}
private static void addVerificationCredentials(Map<String, Object> assertingParty,
RelyingPartyRegistration.AssertingPartyDetails.Builder builder) {
List<String> verificationCertificateLocations = (List<String>) assertingParty.get(ELT_VERIFICATION_CREDENTIAL);
List<Saml2X509Credential> verificationCredentials = new ArrayList<>();
for (String certificateLocation : verificationCertificateLocations) {
verificationCredentials.add(getSaml2VerificationCredential(certificateLocation));
}
builder.verificationX509Credentials((credentials) -> credentials.addAll(verificationCredentials));
}
private static void addEncryptionCredentials(Map<String, Object> assertingParty,
RelyingPartyRegistration.AssertingPartyDetails.Builder builder) {
List<String> encryptionCertificateLocations = (List<String>) assertingParty.get(ELT_ENCRYPTION_CREDENTIAL);
List<Saml2X509Credential> encryptionCredentials = new ArrayList<>();
for (String certificateLocation : encryptionCertificateLocations) {
encryptionCredentials.add(getSaml2EncryptionCredential(certificateLocation));
}
builder.encryptionX509Credentials((credentials) -> credentials.addAll(encryptionCredentials));
}
private static void addVerificationCredentials(Element assertingPartyElt, Map<String, Object> assertingParty) {
List<String> verificationCertificateLocations = new ArrayList<>();
List<Element> verificationCredentialElts = DomUtils.getChildElementsByTagName(assertingPartyElt,
ELT_VERIFICATION_CREDENTIAL);
for (Element verificationCredentialElt : verificationCredentialElts) {
String certificateLocation = verificationCredentialElt.getAttribute(ATT_CERTIFICATE_LOCATION);
verificationCertificateLocations.add(certificateLocation);
}
assertingParty.put(ELT_VERIFICATION_CREDENTIAL, verificationCertificateLocations);
}
private static void addEncryptionCredentials(Element assertingPartyElt, Map<String, Object> assertingParty) {
List<String> encryptionCertificateLocations = new ArrayList<>();
List<Element> encryptionCredentialElts = DomUtils.getChildElementsByTagName(assertingPartyElt,
ELT_VERIFICATION_CREDENTIAL);
for (Element encryptionCredentialElt : encryptionCredentialElts) {
String certificateLocation = encryptionCredentialElt.getAttribute(ATT_CERTIFICATE_LOCATION);
encryptionCertificateLocations.add(certificateLocation);
}
assertingParty.put(ELT_ENCRYPTION_CREDENTIAL, encryptionCertificateLocations);
}
private List<RelyingPartyRegistration> getRelyingPartyRegistrations(Element element,
Map<String, Map<String, Object>> assertingParties, ParserContext parserContext) {
List<Element> relyingPartyRegistrationElts = DomUtils.getChildElementsByTagName(element,
ELT_RELYING_PARTY_REGISTRATION);
List<RelyingPartyRegistration> relyingPartyRegistrations = new ArrayList<>();
for (Element relyingPartyRegistrationElt : relyingPartyRegistrationElts) {
RelyingPartyRegistration.Builder builder = getBuilderFromMetadataLocationIfPossible(
relyingPartyRegistrationElt, assertingParties, parserContext);
addSigningCredentials(relyingPartyRegistrationElt, builder);
addDecryptionCredentials(relyingPartyRegistrationElt, builder);
relyingPartyRegistrations.add(builder.build());
}
return relyingPartyRegistrations;
}
private static RelyingPartyRegistration.Builder getBuilderFromMetadataLocationIfPossible(
Element relyingPartyRegistrationElt, Map<String, Map<String, Object>> assertingParties,
ParserContext parserContext) {
String registrationId = relyingPartyRegistrationElt.getAttribute(ATT_REGISTRATION_ID);
String metadataLocation = relyingPartyRegistrationElt.getAttribute(ATT_METADATA_LOCATION);
String singleLogoutServiceLocation = relyingPartyRegistrationElt
.getAttribute(ATT_SINGLE_LOGOUT_SERVICE_LOCATION);
String singleLogoutServiceResponseLocation = relyingPartyRegistrationElt
.getAttribute(ATT_SINGLE_LOGOUT_SERVICE_RESPONSE_LOCATION);
Saml2MessageBinding singleLogoutServiceBinding = getSingleLogoutServiceBinding(relyingPartyRegistrationElt);
if (StringUtils.hasText(metadataLocation)) {
return RelyingPartyRegistrations.fromMetadataLocation(metadataLocation).registrationId(registrationId)
.singleLogoutServiceLocation(singleLogoutServiceLocation)
.singleLogoutServiceResponseLocation(singleLogoutServiceResponseLocation)
.singleLogoutServiceBinding(singleLogoutServiceBinding);
}
String entityId = relyingPartyRegistrationElt.getAttribute(ATT_ENTITY_ID);
String assertionConsumerServiceLocation = relyingPartyRegistrationElt
.getAttribute(ATT_ASSERTION_CONSUMER_SERVICE_LOCATION);
Saml2MessageBinding assertionConsumerServiceBinding = getAssertionConsumerServiceBinding(
relyingPartyRegistrationElt);
return RelyingPartyRegistration.withRegistrationId(registrationId).entityId(entityId)
.assertionConsumerServiceLocation(assertionConsumerServiceLocation)
.assertionConsumerServiceBinding(assertionConsumerServiceBinding)
.singleLogoutServiceLocation(singleLogoutServiceLocation)
.singleLogoutServiceResponseLocation(singleLogoutServiceResponseLocation)
.singleLogoutServiceBinding(singleLogoutServiceBinding)
.assertingPartyDetails((builder) -> buildAssertingParty(relyingPartyRegistrationElt, assertingParties,
builder, parserContext));
}
private static void buildAssertingParty(Element relyingPartyElt, Map<String, Map<String, Object>> assertingParties,
RelyingPartyRegistration.AssertingPartyDetails.Builder builder, ParserContext parserContext) {
String assertingPartyId = relyingPartyElt.getAttribute(ATT_ASSERTING_PARTY_ID);
if (!assertingParties.containsKey(assertingPartyId)) {
Object source = parserContext.extractSource(relyingPartyElt);
parserContext.getReaderContext()
.error(String.format("Could not find asserting party with id %s", assertingPartyId), source);
}
Map<String, Object> assertingParty = assertingParties.get(assertingPartyId);
String entityId = getAsString(assertingParty, ATT_ENTITY_ID);
String wantAuthnRequestsSigned = getAsString(assertingParty, ATT_WANT_AUTHN_REQUESTS_SIGNED);
String singleSignOnServiceLocation = getAsString(assertingParty, ATT_SINGLE_SIGN_ON_SERVICE_LOCATION);
String singleSignOnServiceBinding = getAsString(assertingParty, ATT_SINGLE_SIGN_ON_SERVICE_BINDING);
Saml2MessageBinding saml2MessageBinding = StringUtils.hasText(singleSignOnServiceBinding)
? Saml2MessageBinding.valueOf(singleSignOnServiceBinding) : Saml2MessageBinding.REDIRECT;
String singleLogoutServiceLocation = getAsString(assertingParty, ATT_SINGLE_LOGOUT_SERVICE_LOCATION);
String singleLogoutServiceResponseLocation = getAsString(assertingParty,
ATT_SINGLE_LOGOUT_SERVICE_RESPONSE_LOCATION);
String singleLogoutServiceBinding = getAsString(assertingParty, ATT_SINGLE_LOGOUT_SERVICE_BINDING);
Saml2MessageBinding saml2LogoutMessageBinding = StringUtils.hasText(singleLogoutServiceBinding)
? Saml2MessageBinding.valueOf(singleLogoutServiceBinding) : Saml2MessageBinding.REDIRECT;
builder.entityId(entityId).wantAuthnRequestsSigned(Boolean.parseBoolean(wantAuthnRequestsSigned))
.singleSignOnServiceLocation(singleSignOnServiceLocation)
.singleSignOnServiceBinding(saml2MessageBinding)
.singleLogoutServiceLocation(singleLogoutServiceLocation)
.singleLogoutServiceResponseLocation(singleLogoutServiceResponseLocation)
.singleLogoutServiceBinding(saml2LogoutMessageBinding);
addSigningAlgorithms(assertingParty, builder);
addVerificationCredentials(assertingParty, builder);
addEncryptionCredentials(assertingParty, builder);
}
private static void addSigningAlgorithms(Map<String, Object> assertingParty,
RelyingPartyRegistration.AssertingPartyDetails.Builder builder) {
String signingAlgorithmsAttr = getAsString(assertingParty, ATT_SIGNING_ALGORITHMS);
if (StringUtils.hasText(signingAlgorithmsAttr)) {
List<String> signingAlgorithms = Arrays.asList(signingAlgorithmsAttr.split(","));
builder.signingAlgorithms((s) -> s.addAll(signingAlgorithms));
}
}
private static void addSigningCredentials(Element relyingPartyRegistrationElt,
RelyingPartyRegistration.Builder builder) {
List<Element> credentialElts = DomUtils.getChildElementsByTagName(relyingPartyRegistrationElt,
ELT_SIGNING_CREDENTIAL);
for (Element credentialElt : credentialElts) {
String privateKeyLocation = credentialElt.getAttribute(ATT_PRIVATE_KEY_LOCATION);
String certificateLocation = credentialElt.getAttribute(ATT_CERTIFICATE_LOCATION);
builder.signingX509Credentials(
(c) -> c.add(getSaml2SigningCredential(privateKeyLocation, certificateLocation)));
}
}
private static void addDecryptionCredentials(Element relyingPartyRegistrationElt,
RelyingPartyRegistration.Builder builder) {
List<Element> credentialElts = DomUtils.getChildElementsByTagName(relyingPartyRegistrationElt,
ELT_DECRYPTION_CREDENTIAL);
for (Element credentialElt : credentialElts) {
String privateKeyLocation = credentialElt.getAttribute(ATT_PRIVATE_KEY_LOCATION);
String certificateLocation = credentialElt.getAttribute(ATT_CERTIFICATE_LOCATION);
Saml2X509Credential credential = getSaml2DecryptionCredential(privateKeyLocation, certificateLocation);
builder.decryptionX509Credentials((c) -> c.add(credential));
}
}
private static String getAsString(Map<String, Object> assertingParty, String key) {
return (String) assertingParty.get(key);
}
private static Saml2MessageBinding getAssertionConsumerServiceBinding(Element relyingPartyRegistrationElt) {
String assertionConsumerServiceBinding = relyingPartyRegistrationElt
.getAttribute(ATT_ASSERTION_CONSUMER_SERVICE_BINDING);
if (StringUtils.hasText(assertionConsumerServiceBinding)) {
return Saml2MessageBinding.valueOf(assertionConsumerServiceBinding);
}
return Saml2MessageBinding.REDIRECT;
}
private static Saml2MessageBinding getSingleLogoutServiceBinding(Element relyingPartyRegistrationElt) {
String singleLogoutServiceBinding = relyingPartyRegistrationElt.getAttribute(ATT_SINGLE_LOGOUT_SERVICE_BINDING);
if (StringUtils.hasText(singleLogoutServiceBinding)) {
return Saml2MessageBinding.valueOf(singleLogoutServiceBinding);
}
return Saml2MessageBinding.POST;
}
private static Saml2X509Credential getSaml2VerificationCredential(String certificateLocation) {
return getSaml2Credential(certificateLocation, Saml2X509Credential.Saml2X509CredentialType.VERIFICATION);
}
private static Saml2X509Credential getSaml2EncryptionCredential(String certificateLocation) {
return getSaml2Credential(certificateLocation, Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION);
}
private static Saml2X509Credential getSaml2SigningCredential(String privateKeyLocation,
String certificateLocation) {
return getSaml2Credential(privateKeyLocation, certificateLocation,
Saml2X509Credential.Saml2X509CredentialType.SIGNING);
}
private static Saml2X509Credential getSaml2DecryptionCredential(String privateKeyLocation,
String certificateLocation) {
return getSaml2Credential(privateKeyLocation, certificateLocation,
Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
}
private static Saml2X509Credential getSaml2Credential(String privateKeyLocation, String certificateLocation,
Saml2X509Credential.Saml2X509CredentialType credentialType) {
RSAPrivateKey privateKey = readPrivateKey(privateKeyLocation);
X509Certificate certificate = readCertificate(certificateLocation);
return new Saml2X509Credential(privateKey, certificate, credentialType);
}
private static Saml2X509Credential getSaml2Credential(String certificateLocation,
Saml2X509Credential.Saml2X509CredentialType credentialType) {
X509Certificate certificate = readCertificate(certificateLocation);
return new Saml2X509Credential(certificate, credentialType);
}
private static RSAPrivateKey readPrivateKey(String privateKeyLocation) {
Resource privateKey = resourceLoader.getResource(privateKeyLocation);
try (InputStream inputStream = privateKey.getInputStream()) {
return RsaKeyConverters.pkcs8().convert(inputStream);
}
catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
}
private static X509Certificate readCertificate(String certificateLocation) {
Resource certificate = resourceLoader.getResource(certificateLocation);
try (InputStream inputStream = certificate.getInputStream()) {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(inputStream);
}
catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
}
}
@@ -133,7 +133,6 @@ import org.springframework.security.web.server.authorization.AuthorizationContex
import org.springframework.security.web.server.authorization.AuthorizationWebFilter;
import org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager;
import org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter;
import org.springframework.security.web.server.authorization.IpAddressReactiveAuthorizationManager;
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
import org.springframework.security.web.server.authorization.ServerWebExchangeDelegatingServerAccessDeniedHandler;
import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository;
@@ -149,12 +148,6 @@ import org.springframework.security.web.server.header.CacheControlServerHttpHead
import org.springframework.security.web.server.header.CompositeServerHttpHeadersWriter;
import org.springframework.security.web.server.header.ContentSecurityPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy;
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy;
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy;
import org.springframework.security.web.server.header.FeaturePolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.HttpHeaderWriterWebFilter;
import org.springframework.security.web.server.header.PermissionsPolicyServerHttpHeadersWriter;
@@ -1689,18 +1682,6 @@ public class ServerHttpSecurity {
return access(AuthenticatedReactiveAuthorizationManager.authenticated());
}
/**
* Require a specific IP address or range using an IP/Netmask (e.g.
* 192.168.1.0/24).
* @param ipAddress the address or range of addresses from which the request
* must come.
* @return the {@link AuthorizeExchangeSpec} to configure
* @since 5.7
*/
public AuthorizeExchangeSpec hasIpAddress(String ipAddress) {
return access(IpAddressReactiveAuthorizationManager.hasIpAddress(ipAddress));
}
/**
* Allows plugging in a custom authorization strategy
* @param manager the authorization manager to use
@@ -2386,17 +2367,10 @@ public class ServerHttpSecurity {
private ReferrerPolicyServerHttpHeadersWriter referrerPolicy = new ReferrerPolicyServerHttpHeadersWriter();
private CrossOriginOpenerPolicyServerHttpHeadersWriter crossOriginOpenerPolicy = new CrossOriginOpenerPolicyServerHttpHeadersWriter();
private CrossOriginEmbedderPolicyServerHttpHeadersWriter crossOriginEmbedderPolicy = new CrossOriginEmbedderPolicyServerHttpHeadersWriter();
private CrossOriginResourcePolicyServerHttpHeadersWriter crossOriginResourcePolicy = new CrossOriginResourcePolicyServerHttpHeadersWriter();
private HeaderSpec() {
this.writers = new ArrayList<>(Arrays.asList(this.cacheControl, this.contentTypeOptions, this.hsts,
this.frameOptions, this.xss, this.featurePolicy, this.permissionsPolicy, this.contentSecurityPolicy,
this.referrerPolicy, this.crossOriginOpenerPolicy, this.crossOriginEmbedderPolicy,
this.crossOriginResourcePolicy));
this.referrerPolicy));
}
/**
@@ -2608,84 +2582,6 @@ public class ServerHttpSecurity {
return this;
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a> header.
* @return the {@link CrossOriginOpenerPolicySpec} to configure
* @since 5.7
* @see CrossOriginOpenerPolicyServerHttpHeadersWriter
*/
public CrossOriginOpenerPolicySpec crossOriginOpenerPolicy() {
return new CrossOriginOpenerPolicySpec();
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a> header.
* @return the {@link HeaderSpec} to customize
* @since 5.7
* @see CrossOriginOpenerPolicyServerHttpHeadersWriter
*/
public HeaderSpec crossOriginOpenerPolicy(
Customizer<CrossOriginOpenerPolicySpec> crossOriginOpenerPolicyCustomizer) {
crossOriginOpenerPolicyCustomizer.customize(new CrossOriginOpenerPolicySpec());
return this;
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a> header.
* @return the {@link CrossOriginEmbedderPolicySpec} to configure
* @since 5.7
* @see CrossOriginEmbedderPolicyServerHttpHeadersWriter
*/
public CrossOriginEmbedderPolicySpec crossOriginEmbedderPolicy() {
return new CrossOriginEmbedderPolicySpec();
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a> header.
* @return the {@link HeaderSpec} to customize
* @since 5.7
* @see CrossOriginEmbedderPolicyServerHttpHeadersWriter
*/
public HeaderSpec crossOriginEmbedderPolicy(
Customizer<CrossOriginEmbedderPolicySpec> crossOriginEmbedderPolicyCustomizer) {
crossOriginEmbedderPolicyCustomizer.customize(new CrossOriginEmbedderPolicySpec());
return this;
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a> header.
* @return the {@link CrossOriginResourcePolicySpec} to configure
* @since 5.7
* @see CrossOriginResourcePolicyServerHttpHeadersWriter
*/
public CrossOriginResourcePolicySpec crossOriginResourcePolicy() {
return new CrossOriginResourcePolicySpec();
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a> header.
* @return the {@link HeaderSpec} to customize
* @since 5.7
* @see CrossOriginResourcePolicyServerHttpHeadersWriter
*/
public HeaderSpec crossOriginResourcePolicy(
Customizer<CrossOriginResourcePolicySpec> crossOriginResourcePolicyCustomizer) {
crossOriginResourcePolicyCustomizer.customize(new CrossOriginResourcePolicySpec());
return this;
}
/**
* Configures cache control headers
*
@@ -3001,99 +2897,6 @@ public class ServerHttpSecurity {
}
/**
* Configures the Cross-Origin-Opener-Policy header
*
* @since 5.7
*/
public final class CrossOriginOpenerPolicySpec {
private CrossOriginOpenerPolicySpec() {
}
/**
* Sets the value to be used in the `Cross-Origin-Opener-Policy` header
* @param openerPolicy a opener policy
* @return the {@link CrossOriginOpenerPolicySpec} to continue configuring
*/
public CrossOriginOpenerPolicySpec policy(CrossOriginOpenerPolicy openerPolicy) {
HeaderSpec.this.crossOriginOpenerPolicy.setPolicy(openerPolicy);
return this;
}
/**
* Allows method chaining to continue configuring the
* {@link ServerHttpSecurity}.
* @return the {@link HeaderSpec} to continue configuring
*/
public HeaderSpec and() {
return HeaderSpec.this;
}
}
/**
* Configures the Cross-Origin-Embedder-Policy header
*
* @since 5.7
*/
public final class CrossOriginEmbedderPolicySpec {
private CrossOriginEmbedderPolicySpec() {
}
/**
* Sets the value to be used in the `Cross-Origin-Embedder-Policy` header
* @param embedderPolicy a opener policy
* @return the {@link CrossOriginEmbedderPolicySpec} to continue configuring
*/
public CrossOriginEmbedderPolicySpec policy(CrossOriginEmbedderPolicy embedderPolicy) {
HeaderSpec.this.crossOriginEmbedderPolicy.setPolicy(embedderPolicy);
return this;
}
/**
* Allows method chaining to continue configuring the
* {@link ServerHttpSecurity}.
* @return the {@link HeaderSpec} to continue configuring
*/
public HeaderSpec and() {
return HeaderSpec.this;
}
}
/**
* Configures the Cross-Origin-Resource-Policy header
*
* @since 5.7
*/
public final class CrossOriginResourcePolicySpec {
private CrossOriginResourcePolicySpec() {
}
/**
* Sets the value to be used in the `Cross-Origin-Resource-Policy` header
* @param resourcePolicy a opener policy
* @return the {@link CrossOriginResourcePolicySpec} to continue configuring
*/
public CrossOriginResourcePolicySpec policy(CrossOriginResourcePolicy resourcePolicy) {
HeaderSpec.this.crossOriginResourcePolicy.setPolicy(resourcePolicy);
return this;
}
/**
* Allows method chaining to continue configuring the
* {@link ServerHttpSecurity}.
* @return the {@link HeaderSpec} to continue configuring
*/
public HeaderSpec and() {
return HeaderSpec.this;
}
}
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2020 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.
@@ -22,7 +22,6 @@ import org.springframework.security.authorization.AuthorizationDecision
import org.springframework.security.authorization.ReactiveAuthorizationManager
import org.springframework.security.core.Authentication
import org.springframework.security.web.server.authorization.AuthorizationContext
import org.springframework.security.web.server.authorization.IpAddressReactiveAuthorizationManager
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers
import org.springframework.security.web.util.matcher.RequestMatcher
@@ -109,13 +108,6 @@ class AuthorizeExchangeDsl {
fun hasAnyAuthority(vararg authorities: String): ReactiveAuthorizationManager<AuthorizationContext> =
AuthorityReactiveAuthorizationManager.hasAnyAuthority<AuthorizationContext>(*authorities)
/**
* Require a specific IP or range of IP addresses.
* @since 5.7
*/
fun hasIpAddress(ipAddress: String): ReactiveAuthorizationManager<AuthorizationContext> =
IpAddressReactiveAuthorizationManager.hasIpAddress(ipAddress)
/**
* Require an authenticated user.
*/
@@ -1,42 +0,0 @@
/*
* Copyright 2002-2021 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.web.server
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Embedder-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@ServerSecurityMarker
class ServerCrossOriginEmbedderPolicyDsl {
var policy: CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy? = null
internal fun get(): (ServerHttpSecurity.HeaderSpec.CrossOriginEmbedderPolicySpec) -> Unit {
return { crossOriginEmbedderPolicy ->
policy?.also {
crossOriginEmbedderPolicy.policy(policy)
}
}
}
}
@@ -1,42 +0,0 @@
/*
* Copyright 2002-2021 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.web.server
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Opener-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@ServerSecurityMarker
class ServerCrossOriginOpenerPolicyDsl {
var policy: CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy? = null
internal fun get(): (ServerHttpSecurity.HeaderSpec.CrossOriginOpenerPolicySpec) -> Unit {
return { crossOriginOpenerPolicy ->
policy?.also {
crossOriginOpenerPolicy.policy(policy)
}
}
}
}
@@ -1,42 +0,0 @@
/*
* Copyright 2002-2021 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.web.server
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Resource-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@ServerSecurityMarker
class ServerCrossOriginResourcePolicyDsl {
var policy: CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy? = null
internal fun get(): (ServerHttpSecurity.HeaderSpec.CrossOriginResourcePolicySpec) -> Unit {
return { crossOriginResourcePolicy ->
policy?.also {
crossOriginResourcePolicy.policy(policy)
}
}
}
}
@@ -16,12 +16,7 @@
package org.springframework.security.config.web.server
import org.springframework.security.web.server.header.CacheControlServerHttpHeadersWriter
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
import org.springframework.security.web.server.header.ReferrerPolicyServerHttpHeadersWriter
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter
import org.springframework.security.web.server.header.XXssProtectionServerHttpHeadersWriter
import org.springframework.security.web.server.header.*
/**
* A Kotlin DSL to configure [ServerHttpSecurity] headers using idiomatic Kotlin code.
@@ -40,9 +35,6 @@ class ServerHeadersDsl {
private var referrerPolicy: ((ServerHttpSecurity.HeaderSpec.ReferrerPolicySpec) -> Unit)? = null
private var featurePolicyDirectives: String? = null
private var permissionsPolicy: ((ServerHttpSecurity.HeaderSpec.PermissionsPolicySpec) -> Unit)? = null
private var crossOriginOpenerPolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginOpenerPolicySpec) -> Unit)? = null
private var crossOriginEmbedderPolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginEmbedderPolicySpec) -> Unit)? = null
private var crossOriginResourcePolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginResourcePolicySpec) -> Unit)? = null
private var disabled = false
@@ -165,39 +157,6 @@ class ServerHeadersDsl {
this.permissionsPolicy = ServerPermissionsPolicyDsl().apply(permissionsPolicyConfig).get()
}
/**
* 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.
*
* @since 5.7
* @param crossOriginOpenerPolicyConfig the customization to apply to the header
*/
fun crossOriginOpenerPolicy(crossOriginOpenerPolicyConfig: ServerCrossOriginOpenerPolicyDsl.() -> Unit) {
this.crossOriginOpenerPolicy = ServerCrossOriginOpenerPolicyDsl().apply(crossOriginOpenerPolicyConfig).get()
}
/**
* 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.
*
* @since 5.7
* @param crossOriginEmbedderPolicyConfig the customization to apply to the header
*/
fun crossOriginEmbedderPolicy(crossOriginEmbedderPolicyConfig: ServerCrossOriginEmbedderPolicyDsl.() -> Unit) {
this.crossOriginEmbedderPolicy = ServerCrossOriginEmbedderPolicyDsl().apply(crossOriginEmbedderPolicyConfig).get()
}
/**
* 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.
*
* @since 5.7
* @param crossOriginResourcePolicyConfig the customization to apply to the header
*/
fun crossOriginResourcePolicy(crossOriginResourcePolicyConfig: ServerCrossOriginResourcePolicyDsl.() -> Unit) {
this.crossOriginResourcePolicy = ServerCrossOriginResourcePolicyDsl().apply(crossOriginResourcePolicyConfig).get()
}
/**
* Disables HTTP response headers.
*/
@@ -235,15 +194,6 @@ class ServerHeadersDsl {
referrerPolicy?.also {
headers.referrerPolicy(referrerPolicy)
}
crossOriginOpenerPolicy?.also {
headers.crossOriginOpenerPolicy(crossOriginOpenerPolicy)
}
crossOriginEmbedderPolicy?.also {
headers.crossOriginEmbedderPolicy(crossOriginEmbedderPolicy)
}
crossOriginResourcePolicy?.also {
headers.crossOriginResourcePolicy(crossOriginResourcePolicy)
}
if (disabled) {
headers.disable()
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2020 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.
@@ -17,8 +17,6 @@
package org.springframework.security.config.web.servlet
import org.springframework.http.HttpMethod
import org.springframework.security.authorization.AuthorizationManager
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
import org.springframework.security.web.util.matcher.AnyRequestMatcher
import org.springframework.security.web.util.matcher.RequestMatcher
@@ -38,25 +36,14 @@ abstract class AbstractRequestMatcherDsl {
protected data class MatcherAuthorizationRule(val matcher: RequestMatcher,
override val rule: String) : AuthorizationRule(rule)
protected data class MatcherAuthorizationManagerRule(val matcher: RequestMatcher,
override val rule: AuthorizationManager<RequestAuthorizationContext>) : AuthorizationManagerRule(rule)
protected data class PatternAuthorizationRule(val pattern: String,
val patternType: PatternType,
val servletPath: String? = null,
val httpMethod: HttpMethod? = null,
override val rule: String) : AuthorizationRule(rule)
protected data class PatternAuthorizationManagerRule(val pattern: String,
val patternType: PatternType,
val servletPath: String? = null,
val httpMethod: HttpMethod? = null,
override val rule: AuthorizationManager<RequestAuthorizationContext>) : AuthorizationManagerRule(rule)
protected abstract class AuthorizationRule(open val rule: String)
protected abstract class AuthorizationManagerRule(open val rule: AuthorizationManager<RequestAuthorizationContext>)
protected enum class PatternType {
ANT, MVC
}
@@ -1,260 +0,0 @@
/*
* Copyright 2002-2022 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.web.servlet
import org.springframework.http.HttpMethod
import org.springframework.security.authorization.AuthenticatedAuthorizationManager
import org.springframework.security.authorization.AuthorityAuthorizationManager
import org.springframework.security.authorization.AuthorizationDecision
import org.springframework.security.authorization.AuthorizationManager
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer
import org.springframework.security.core.Authentication
import org.springframework.security.web.access.intercept.AuthorizationFilter
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
import org.springframework.security.web.util.matcher.AnyRequestMatcher
import org.springframework.security.web.util.matcher.RequestMatcher
import org.springframework.util.ClassUtils
import java.util.function.Supplier
/**
* A Kotlin DSL to configure [HttpSecurity] request authorization using idiomatic Kotlin code.
*
* @author Yuriy Savchenko
* @since 5.7
* @property shouldFilterAllDispatcherTypes whether the [AuthorizationFilter] should filter all dispatcher types
*/
class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl() {
var shouldFilterAllDispatcherTypes: Boolean? = null
private val authorizationRules = mutableListOf<AuthorizationManagerRule>()
private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"
private val MVC_PRESENT = ClassUtils.isPresent(
HANDLER_MAPPING_INTROSPECTOR,
AuthorizeHttpRequestsDsl::class.java.classLoader)
private val PATTERN_TYPE = if (MVC_PRESENT) PatternType.MVC else PatternType.ANT
/**
* Adds a request authorization rule.
*
* @param matches the [RequestMatcher] to match incoming requests against
* @param access the [AuthorizationManager] to secure the matching request
* (i.e. created via hasAuthority("ROLE_USER"))
*/
fun authorize(matches: RequestMatcher = AnyRequestMatcher.INSTANCE,
access: AuthorizationManager<RequestAuthorizationContext>) {
authorizationRules.add(MatcherAuthorizationManagerRule(matches, access))
}
/**
* Adds a request authorization rule for an endpoint matching the provided
* pattern.
* If Spring MVC is on the classpath, it will use an MVC matcher.
* If Spring MVC is not on the classpath, it will use an ant matcher.
* The MVC 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 current request will not be processed by Spring MVC, a reasonable default
* using the pattern as an ant pattern will be used.
*
* @param pattern the pattern to match incoming requests against.
* @param access the [AuthorizationManager] to secure the matching request
* (i.e. created via hasAuthority("ROLE_USER"))
*/
fun authorize(pattern: String,
access: AuthorizationManager<RequestAuthorizationContext>) {
authorizationRules.add(
PatternAuthorizationManagerRule(
pattern = pattern,
patternType = PATTERN_TYPE,
rule = access
)
)
}
/**
* Adds a request authorization rule for an endpoint matching the provided
* pattern.
* If Spring MVC is on the classpath, it will use an MVC matcher.
* If Spring MVC is not on the classpath, it will use an ant matcher.
* The MVC 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 current request will not be processed by Spring MVC, a reasonable default
* using the pattern as an ant pattern will be used.
*
* @param method the HTTP method to match the income requests against.
* @param pattern the pattern to match incoming requests against.
* @param access the [AuthorizationManager] to secure the matching request
* (i.e. created via hasAuthority("ROLE_USER"))
*/
fun authorize(method: HttpMethod,
pattern: String,
access: AuthorizationManager<RequestAuthorizationContext>) {
authorizationRules.add(
PatternAuthorizationManagerRule(
pattern = pattern,
patternType = PATTERN_TYPE,
httpMethod = method,
rule = access
)
)
}
/**
* Adds a request authorization rule for an endpoint matching the provided
* pattern.
* If Spring MVC is on the classpath, it will use an MVC matcher.
* If Spring MVC is not on the classpath, it will use an ant matcher.
* The MVC 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 current request will not be processed by Spring MVC, a reasonable default
* using the pattern as an ant pattern will be used.
*
* @param pattern the pattern to match incoming requests against.
* @param servletPath the servlet path to match incoming requests against. This
* only applies when using an MVC pattern matcher.
* @param access the [AuthorizationManager] to secure the matching request
* (i.e. created via hasAuthority("ROLE_USER"))
*/
fun authorize(pattern: String,
servletPath: String,
access: AuthorizationManager<RequestAuthorizationContext>) {
authorizationRules.add(
PatternAuthorizationManagerRule(
pattern = pattern,
patternType = PATTERN_TYPE,
servletPath = servletPath,
rule = access
)
)
}
/**
* Adds a request authorization rule for an endpoint matching the provided
* pattern.
* If Spring MVC is on the classpath, it will use an MVC matcher.
* If Spring MVC is not on the classpath, it will use an ant matcher.
* The MVC 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 current request will not be processed by Spring MVC, a reasonable default
* using the pattern as an ant pattern will be used.
*
* @param method the HTTP method to match the income requests against.
* @param pattern the pattern to match incoming requests against.
* @param servletPath the servlet path to match incoming requests against. This
* only applies when using an MVC pattern matcher.
* @param access the [AuthorizationManager] to secure the matching request
* (i.e. created via hasAuthority("ROLE_USER"))
*/
fun authorize(method: HttpMethod,
pattern: String,
servletPath: String,
access: AuthorizationManager<RequestAuthorizationContext>) {
authorizationRules.add(
PatternAuthorizationManagerRule(
pattern = pattern,
patternType = PATTERN_TYPE,
servletPath = servletPath,
httpMethod = method,
rule = access
)
)
}
/**
* Specify that URLs require a particular authority.
*
* @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
* @return the [AuthorizationManager] with the provided authority
*/
fun hasAuthority(authority: String): AuthorizationManager<RequestAuthorizationContext> {
return AuthorityAuthorizationManager.hasAuthority(authority)
}
/**
* Specify that URLs require any of the provided authorities.
*
* @param authorities the authorities to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
* @return the [AuthorizationManager] with the provided authorities
*/
fun hasAnyAuthority(vararg authorities: String): AuthorizationManager<RequestAuthorizationContext> {
return AuthorityAuthorizationManager.hasAnyAuthority(*authorities)
}
/**
* Specify that URLs require a particular role.
*
* @param role the role to require (i.e. USER, ADMIN, etc).
* @return the [AuthorizationManager] with the provided role
*/
fun hasRole(role: String): AuthorizationManager<RequestAuthorizationContext> {
return AuthorityAuthorizationManager.hasRole(role)
}
/**
* Specify that URLs require any of the provided roles.
*
* @param roles the roles to require (i.e. USER, ADMIN, etc).
* @return the [AuthorizationManager] with the provided roles
*/
fun hasAnyRole(vararg roles: String): AuthorizationManager<RequestAuthorizationContext> {
return AuthorityAuthorizationManager.hasAnyRole(*roles)
}
/**
* Specify that URLs are allowed by anyone.
*/
val permitAll: AuthorizationManager<RequestAuthorizationContext> =
AuthorizationManager { _: Supplier<Authentication>, _: RequestAuthorizationContext -> AuthorizationDecision(true) }
/**
* Specify that URLs are not allowed by anyone.
*/
val denyAll: AuthorizationManager<RequestAuthorizationContext> =
AuthorizationManager { _: Supplier<Authentication>, _: RequestAuthorizationContext -> AuthorizationDecision(false) }
/**
* Specify that URLs are allowed by any authenticated user.
*/
val authenticated: AuthorizationManager<RequestAuthorizationContext> =
AuthenticatedAuthorizationManager.authenticated()
internal fun get(): (AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry) -> Unit {
return { requests ->
authorizationRules.forEach { rule ->
when (rule) {
is MatcherAuthorizationManagerRule -> requests.requestMatchers(rule.matcher).access(rule.rule)
is PatternAuthorizationManagerRule -> {
when (rule.patternType) {
PatternType.ANT -> requests.antMatchers(rule.httpMethod, rule.pattern).access(rule.rule)
PatternType.MVC -> requests.mvcMatchers(rule.httpMethod, rule.pattern)
.apply { if (rule.servletPath != null) servletPath(rule.servletPath) }
.access(rule.rule)
}
}
}
}
shouldFilterAllDispatcherTypes?.also { shouldFilter ->
requests.shouldFilterAllDispatcherTypes(shouldFilter)
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2020 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.
@@ -54,7 +54,7 @@ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() {
* Adds a request authorization rule for an endpoint matching the provided
* pattern.
* If Spring MVC is on the classpath, it will use an MVC matcher.
* If Spring MVC is not on the classpath, it will use an ant matcher.
* If Spring MVC is not an the classpath, it will use an ant matcher.
* The MVC 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.
@@ -75,7 +75,7 @@ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() {
* Adds a request authorization rule for an endpoint matching the provided
* pattern.
* If Spring MVC is on the classpath, it will use an MVC matcher.
* If Spring MVC is not on the classpath, it will use an ant matcher.
* If Spring MVC is not an the classpath, it will use an ant matcher.
* The MVC 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.
@@ -98,7 +98,7 @@ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() {
* Adds a request authorization rule for an endpoint matching the provided
* pattern.
* If Spring MVC is on the classpath, it will use an MVC matcher.
* If Spring MVC is not on the classpath, it will use an ant matcher.
* If Spring MVC is not an the classpath, it will use an ant matcher.
* The MVC 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.
@@ -122,7 +122,7 @@ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() {
* Adds a request authorization rule for an endpoint matching the provided
* pattern.
* If Spring MVC is on the classpath, it will use an MVC matcher.
* If Spring MVC is not on the classpath, it will use an ant matcher.
* If Spring MVC is not an the classpath, it will use an ant matcher.
* The MVC 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.
@@ -154,7 +154,7 @@ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() {
fun hasAuthority(authority: String) = "hasAuthority('$authority')"
/**
* Specify that URLs require any number of authorities.
* Specify that URLs requires any of a number authorities.
*
* @param authorities the authorities to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
* @return the SpEL expression "hasAnyAuthority" with the given authorities as a
@@ -175,7 +175,7 @@ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() {
fun hasRole(role: String) = "hasRole('$role')"
/**
* Specify that URLs require any number of roles.
* Specify that URLs requires any of a number roles.
*
* @param roles the roles to require (i.e. USER, ADMIN, etc).
* @return the SpEL expression "hasAnyRole" with the given roles as a
@@ -42,9 +42,6 @@ class HeadersDsl {
private var referrerPolicy: ((HeadersConfigurer<HttpSecurity>.ReferrerPolicyConfig) -> Unit)? = null
private var featurePolicyDirectives: String? = null
private var permissionsPolicy: ((HeadersConfigurer<HttpSecurity>.PermissionsPolicyConfig) -> Unit)? = null
private var crossOriginOpenerPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit)? = null
private var crossOriginEmbedderPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginEmbedderPolicyConfig) -> Unit)? = null
private var crossOriginResourcePolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginResourcePolicyConfig) -> Unit)? = null
private var disabled = false
private var headerWriters = mutableListOf<HeaderWriter>()
@@ -184,54 +181,6 @@ class HeadersDsl {
this.permissionsPolicy = PermissionsPolicyDsl().apply(permissionsPolicyConfig).get()
}
/**
* 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>
* Calling this method automatically enables (includes) the Cross-Origin-Opener-Policy
* header in the response using the supplied policy.
* <p>
*
* @since 5.7
* @param crossOriginOpenerPolicyConfig the customization to apply to the header
*/
fun crossOriginOpenerPolicy(crossOriginOpenerPolicyConfig: CrossOriginOpenerPolicyDsl.() -> Unit) {
this.crossOriginOpenerPolicy = CrossOriginOpenerPolicyDsl().apply(crossOriginOpenerPolicyConfig).get()
}
/**
* 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>
* Calling this method automatically enables (includes) the Cross-Origin-Embedder-Policy
* header in the response using the supplied policy.
* <p>
*
* @since 5.7
* @param crossOriginEmbedderPolicyConfig the customization to apply to the header
*/
fun crossOriginEmbedderPolicy(crossOriginEmbedderPolicyConfig: CrossOriginEmbedderPolicyDsl.() -> Unit) {
this.crossOriginEmbedderPolicy = CrossOriginEmbedderPolicyDsl().apply(crossOriginEmbedderPolicyConfig).get()
}
/**
* Configures the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a> header.
*
* <p>
* Calling this method automatically enables (includes) the Cross-Origin-Resource-Policy
* header in the response using the supplied policy.
* <p>
*
* @since 5.7
* @param crossOriginResourcePolicyConfig the customization to apply to the header
*/
fun crossOriginResourcePolicy(crossOriginResourcePolicyConfig: CrossOriginResourcePolicyDsl.() -> Unit) {
this.crossOriginResourcePolicy = CrossOriginResourcePolicyDsl().apply(crossOriginResourcePolicyConfig).get()
}
/**
* Adds a [HeaderWriter] instance.
*
@@ -289,15 +238,6 @@ class HeadersDsl {
permissionsPolicy?.also {
headers.permissionsPolicy(permissionsPolicy)
}
crossOriginOpenerPolicy?.also {
headers.crossOriginOpenerPolicy(crossOriginOpenerPolicy)
}
crossOriginEmbedderPolicy?.also {
headers.crossOriginEmbedderPolicy(crossOriginEmbedderPolicy)
}
crossOriginResourcePolicy?.also {
headers.crossOriginResourcePolicy(crossOriginResourcePolicy)
}
headerWriters.forEach { headerWriter ->
headers.addHeaderWriter(headerWriter)
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2021 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.
@@ -38,8 +38,8 @@ import javax.servlet.http.HttpServletRequest
* override fun configure(http: HttpSecurity) {
* http {
* authorizeRequests {
* authorize("/public", permitAll)
* authorize(anyRequest, authenticated)
* request("/public", permitAll)
* request(anyRequest, authenticated)
* }
* formLogin {
* loginPage = "/log-in"
@@ -50,7 +50,6 @@ import javax.servlet.http.HttpServletRequest
* ```
*
* @author Eleftheria Stein
* @author Norbert Nowak
* @since 5.3
* @param httpConfiguration the configurations to apply to [HttpSecurity]
*/
@@ -102,10 +101,7 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
fun securityMatcher(vararg pattern: String) {
val mvcPresent = ClassUtils.isPresent(
HANDLER_MAPPING_INTROSPECTOR,
AuthorizeRequestsDsl::class.java.classLoader) ||
ClassUtils.isPresent(
HANDLER_MAPPING_INTROSPECTOR,
AuthorizeHttpRequestsDsl::class.java.classLoader)
AuthorizeRequestsDsl::class.java.classLoader)
this.http.requestMatchers {
if (mvcPresent) {
it.mvcMatchers(*pattern)
@@ -185,8 +181,8 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
* override fun configure(http: HttpSecurity) {
* http {
* authorizeRequests {
* authorize("/public", permitAll)
* authorize(anyRequest, authenticated)
* request("/public", permitAll)
* request(anyRequest, authenticated)
* }
* }
* }
@@ -202,38 +198,6 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
this.http.authorizeRequests(authorizeRequestsCustomizer)
}
/**
* Allows restricting access based upon the [HttpServletRequest]
*
* Example:
*
* ```
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* authorizeHttpRequests {
* authorize("/public", permitAll)
* authorize(anyRequest, authenticated)
* }
* }
* return http.build()
* }
* }
* ```
*
* @param authorizeHttpRequestsConfiguration custom configuration that specifies
* access for requests
* @see [AuthorizeHttpRequestsDsl]
* @since 5.7
*/
fun authorizeHttpRequests(authorizeHttpRequestsConfiguration: AuthorizeHttpRequestsDsl.() -> Unit) {
val authorizeHttpRequestsCustomizer = AuthorizeHttpRequestsDsl().apply(authorizeHttpRequestsConfiguration).get()
this.http.authorizeHttpRequests(authorizeHttpRequestsCustomizer)
}
/**
* Enables HTTP basic authentication.
*
@@ -906,32 +870,4 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
init()
authenticationManager?.also { this.http.authenticationManager(authenticationManager) }
}
/**
* Enables security context configuration.
*
* Example:
*
* ```
* @EnableWebSecurity
* class SecurityConfig : WebSecurityConfigurerAdapter() {
*
* override fun configure(http: HttpSecurity) {
* http {
* securityContext {
* securityContextRepository = SECURITY_CONTEXT_REPOSITORY
* }
* }
* }
* }
* ```
* @author Norbert Nowak
* @since 5.7
* @param securityContextConfiguration configuration to be applied to Security Context
* @see [SecurityContextDsl]
*/
fun securityContext(securityContextConfiguration: SecurityContextDsl.() -> Unit) {
val securityContextCustomizer = SecurityContextDsl().apply(securityContextConfiguration).get()
this.http.securityContext(securityContextCustomizer)
}
}
@@ -1,42 +0,0 @@
/*
* Copyright 2002-2022 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.web.servlet
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configurers.SecurityContextConfigurer
import org.springframework.security.web.context.SecurityContextRepository
/**
* A Kotlin DSL to configure [HttpSecurity] security context using idiomatic Kotlin code.
*
* @property securityContextRepository the [SecurityContextRepository] used for persisting [org.springframework.security.core.context.SecurityContext] between requests
* @author Norbert Nowak
* @since 5.7
*/
@SecurityMarker
class SecurityContextDsl {
var securityContextRepository: SecurityContextRepository? = null
var requireExplicitSave: Boolean? = null
internal fun get(): (SecurityContextConfigurer<HttpSecurity>) -> Unit {
return { securityContext ->
securityContextRepository?.also { securityContext.securityContextRepository(it) }
requireExplicitSave?.also { securityContext.requireExplicitSave(it) }
}
}
}
@@ -1,43 +0,0 @@
/*
* Copyright 2002-2021 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.web.servlet.headers
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Embedder-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@HeadersSecurityMarker
class CrossOriginEmbedderPolicyDsl {
var policy: CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy? = null
internal fun get(): (HeadersConfigurer<HttpSecurity>.CrossOriginEmbedderPolicyConfig) -> Unit {
return { crossOriginEmbedderPolicy ->
policy?.also {
crossOriginEmbedderPolicy.policy(policy)
}
}
}
}
@@ -1,43 +0,0 @@
/*
* Copyright 2002-2021 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.web.servlet.headers
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Opener-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@HeadersSecurityMarker
class CrossOriginOpenerPolicyDsl {
var policy: CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy? = null
internal fun get(): (HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit {
return { crossOriginOpenerPolicy ->
policy?.also {
crossOriginOpenerPolicy.policy(policy)
}
}
}
}
@@ -1,43 +0,0 @@
/*
* Copyright 2002-2021 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.web.servlet.headers
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Resource-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@HeadersSecurityMarker
class CrossOriginResourcePolicyDsl {
var policy: CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy? = null
internal fun get(): (HeadersConfigurer<HttpSecurity>.CrossOriginResourcePolicyConfig) -> Unit {
return { crossOriginResourcePolicy ->
policy?.also {
crossOriginResourcePolicy.policy(policy)
}
}
}
}
@@ -1,5 +1,4 @@
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-5.7.xsd
http\://www.springframework.org/schema/security/spring-security-5.7.xsd=org/springframework/security/config/spring-security-5.7.xsd
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-5.6.xsd
http\://www.springframework.org/schema/security/spring-security-5.6.xsd=org/springframework/security/config/spring-security-5.6.xsd
http\://www.springframework.org/schema/security/spring-security-5.5.xsd=org/springframework/security/config/spring-security-5.5.xsd
http\://www.springframework.org/schema/security/spring-security-5.4.xsd=org/springframework/security/config/spring-security-5.4.xsd
@@ -18,8 +17,7 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-5.7.xsd
https\://www.springframework.org/schema/security/spring-security-5.7.xsd=org/springframework/security/config/spring-security-5.7.xsd
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-5.6.xsd
https\://www.springframework.org/schema/security/spring-security-5.6.xsd=org/springframework/security/config/spring-security-5.6.xsd
https\://www.springframework.org/schema/security/spring-security-5.5.xsd=org/springframework/security/config/spring-security-5.5.xsd
https\://www.springframework.org/schema/security/spring-security-5.4.xsd=org/springframework/security/config/spring-security-5.4.xsd

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