1
0
mirror of synced 2026-07-09 12:50:19 +00:00

Compare commits

...

151 Commits

Author SHA1 Message Date
Rob Winch 02b8d4cb32 rm .github/workflows for unsupported branch 2025-05-02 12:35:27 -05:00
Rob Winch e0655bee7c rm merge-dependabot-pr.yml from Unsupported Branch 2025-04-25 13:16:06 -05:00
Marcus Hert Da Coregio 1a90041271 Only Merge PRs from Original Repository
(cherry picked from commit 31babecfbd)
2024-07-26 14:44:35 -03:00
Marcus Hert Da Coregio 2ee188ee36 Change Skip Condition
(cherry picked from commit 4c12940304)
2024-07-26 14:44:35 -03:00
Josh Cummings 5bfd1f59d1 Merge branch '5.8.x' into 6.1.x 2024-05-20 16:21:04 -06:00
Josh Cummings 4b10c2daac Turn Off Build Scans
Currently, --scan is preventing PR builds from completing.

Issue gh-15120
2024-05-20 16:20:43 -06:00
Josh Cummings 0e4d29763f Merge branch '5.8.x' into 6.1.x 2024-05-20 12:42:52 -06:00
Josh Cummings 63e24a3026 Adjust JavaDoc Classpath
Issue gh-14931
2024-05-20 12:42:01 -06:00
Marcus Hert Da Coregio 514600721c Merge branch '5.8.x' into 6.1.x 2024-05-20 13:51:57 -03:00
github-actions[bot] 2563b854ea Update Antora Spring UI to v0.4.15 2024-05-20 13:51:29 -03:00
github-actions[bot] 9027dceb71 Update Antora Spring UI to v0.4.15 2024-05-20 13:51:18 -03:00
dependabot[bot] d61a85f74b Bump com.gradle.develocity from 3.17.3 to 3.17.4
Bumps com.gradle.develocity from 3.17.3 to 3.17.4.

---
updated-dependencies:
- dependency-name: com.gradle.develocity
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-19 20:39:20 -07:00
dependabot[bot] 8b3d33ed64 Bump org.springframework:spring-framework-bom from 6.0.19 to 6.0.20
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.0.19 to 6.0.20.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.0.19...v6.0.20)

---
updated-dependencies:
- dependency-name: org.springframework:spring-framework-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-16 20:31:22 -07:00
dependabot[bot] defe27d53e Bump io.mockk:mockk from 1.13.10 to 1.13.11
Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.10 to 1.13.11.
- [Release notes](https://github.com/mockk/mockk/releases)
- [Commits](https://github.com/mockk/mockk/compare/1.13.10...1.13.11)

---
updated-dependencies:
- dependency-name: io.mockk:mockk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-16 20:31:02 -07:00
dependabot[bot] c5b86370ff Bump org-eclipse-jetty from 11.0.20 to 11.0.21
Bumps `org-eclipse-jetty` from 11.0.20 to 11.0.21.

Updates `org.eclipse.jetty:jetty-server` from 11.0.20 to 11.0.21

Updates `org.eclipse.jetty:jetty-servlet` from 11.0.20 to 11.0.21

---
updated-dependencies:
- dependency-name: org.eclipse.jetty:jetty-server
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.eclipse.jetty:jetty-servlet
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-16 20:29:46 -07:00
dependabot[bot] da796e44e5 Bump io.projectreactor:reactor-bom from 2022.0.18 to 2022.0.19
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2022.0.18 to 2022.0.19.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2022.0.18...2022.0.19)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-14 20:24:35 -07:00
Marcus Hert Da Coregio f5b9dc3282 Merge branch '5.8.x' into 6.1.x
Closes gh-15062
2024-05-13 11:22:09 -03:00
Patrick Schmidt 1ebd663253 doc: added hint to declare GrantedAuthorityDefaults as infrastructure bean
Closes gh-14779
2024-05-13 11:19:41 -03:00
Marcus Hert Da Coregio a8c60393f1 Merge branch '5.8.x' into 6.1.x
Closes gh-15059
2024-05-13 08:53:01 -03:00
Marcus Hert Da Coregio 09198447af Attach Antora Docs to Pull Requests
Closes gh-14992
2024-05-13 08:50:24 -03:00
dependabot[bot] 9ebee3e984 Bump com.gradle.develocity from 3.17.2 to 3.17.3
Bumps com.gradle.develocity from 3.17.2 to 3.17.3.

---
updated-dependencies:
- dependency-name: com.gradle.develocity
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-12 21:01:01 -07:00
dependabot[bot] 60e3f27211 Bump org-aspectj from 1.9.22 to 1.9.22.1
Bumps `org-aspectj` from 1.9.22 to 1.9.22.1.

Updates `org.aspectj:aspectjrt` from 1.9.22 to 1.9.22.1
- [Release notes](https://github.com/eclipse/org.aspectj/releases)
- [Commits](https://github.com/eclipse/org.aspectj/commits)

Updates `org.aspectj:aspectjweaver` from 1.9.22 to 1.9.22.1
- [Release notes](https://github.com/eclipse/org.aspectj/releases)
- [Commits](https://github.com/eclipse/org.aspectj/commits)

---
updated-dependencies:
- dependency-name: org.aspectj:aspectjrt
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.aspectj:aspectjweaver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-12 20:59:55 -07:00
Steve Riesenberg f7650b3ec0 Merge branch '5.8.x' into 6.1.x
Closes gh-15037
2024-05-09 13:41:05 -05:00
Steve Riesenberg e1ec77a7a1 Add Build Updates section to generated release notes
Closes gh-14485
2024-05-09 13:40:25 -05:00
Steve Riesenberg 16e0d61005 Use correct API docs URL
Closes gh-15030
2024-05-08 15:58:45 -05:00
dependabot[bot] befa003f94 Bump io.spring.ge.conventions from 0.0.16 to 0.0.17
Bumps [io.spring.ge.conventions](https://github.com/spring-io/gradle-enterprise-conventions) from 0.0.16 to 0.0.17.
- [Release notes](https://github.com/spring-io/gradle-enterprise-conventions/releases)
- [Commits](https://github.com/spring-io/gradle-enterprise-conventions/compare/v0.0.16...v0.0.17)

---
updated-dependencies:
- dependency-name: io.spring.ge.conventions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-08 10:07:54 -05:00
Steve Riesenberg 74a77d2f72 Migrate to com.gradle.develocity plugin
Issue gh-15021
2024-05-08 10:07:53 -05:00
Steve Riesenberg a80fdee533 Update Gradle Enterprise plugin to 3.17.2
Issue gh-15020
2024-05-08 10:07:53 -05:00
Steve Riesenberg 53b581bb8c Merge branch '5.8.x' into 6.1.x 2024-05-08 10:05:03 -05:00
dependabot[bot] d686037419 Bump io.spring.ge.conventions from 0.0.16 to 0.0.17
Bumps [io.spring.ge.conventions](https://github.com/spring-io/gradle-enterprise-conventions) from 0.0.16 to 0.0.17.
- [Release notes](https://github.com/spring-io/gradle-enterprise-conventions/releases)
- [Commits](https://github.com/spring-io/gradle-enterprise-conventions/compare/v0.0.16...v0.0.17)

---
updated-dependencies:
- dependency-name: io.spring.ge.conventions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-08 10:03:34 -05:00
Steve Riesenberg 5c8311b7d3 Migrate to com.gradle.develocity plugin
Issue gh-15021
2024-05-08 10:03:34 -05:00
Steve Riesenberg d86545dd41 Update Gradle Enterprise plugin to 3.17.2
Issue gh-15020
2024-05-08 09:56:05 -05:00
Steve Riesenberg ee1031356a Polish RELEASE.adoc 2024-05-06 16:04:35 -05:00
Steve Riesenberg f74aeaffa1 Update RELEASE.adoc for release automation 2024-05-03 17:03:21 -05:00
dependabot[bot] ec1b15ed68 Bump com.github.spullara.mustache.java:compiler from 0.9.12 to 0.9.13
Bumps [com.github.spullara.mustache.java:compiler](https://github.com/spullara/mustache.java) from 0.9.12 to 0.9.13.
- [Commits](https://github.com/spullara/mustache.java/compare/mustache.java-0.9.12...mustache.java-0.9.13)

---
updated-dependencies:
- dependency-name: com.github.spullara.mustache.java:compiler
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-01 20:20:49 -07:00
Marcus Hert Da Coregio 93aa48f863 Merge branch '5.8.x' into 6.1.x
Closes gh-14994
2024-04-30 08:58:59 -03:00
Angel Gruevski ce995a0178 Correct a mistake in the documentation related to RequestCacheAwareFilter
Corrected a mistake in the documentation for the Spring Architecture where it was mentioned that RequestCacheAwareFilter is used to save the HttpServletRequest instead of the ExceptionTranslationFilter

Closes gh-14855
2024-04-30 08:58:25 -03:00
dependabot[bot] bbc5c5ce84 Bump com.github.spullara.mustache.java:compiler from 0.9.11 to 0.9.12
Bumps [com.github.spullara.mustache.java:compiler](https://github.com/spullara/mustache.java) from 0.9.11 to 0.9.12.
- [Commits](https://github.com/spullara/mustache.java/compare/mustache.java-0.9.11...mustache.java-0.9.12)

---
updated-dependencies:
- dependency-name: com.github.spullara.mustache.java:compiler
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-29 20:34:16 -07:00
Josh Cummings 1b8cf6cc55 Merge branch '5.8.x' into 6.1.x 2024-04-26 17:21:06 -06:00
Josh Cummings e5ee45d568 Fix Import Error
Issue gh-14880
2024-04-26 17:20:53 -06:00
Josh Cummings 38ae090d3d Merge branch '5.8.x' into 6.1.x
Closes gh-14973
2024-04-26 17:13:39 -06:00
Abimael Sergio 3b9991fc89 Improve PasswordEncoder Error Messaging
Closes gh-14880
2024-04-26 17:13:17 -06:00
Josh Cummings 1ecb036fba Merge branch '5.8.x' into 6.1.x 2024-04-26 17:09:05 -06:00
sheheryarumair 0e211382ee Remove useBase64 parameter 2024-04-26 17:05:49 -06:00
Josh Cummings 2477c22674 Fix Role Name Typo
Closes gh-14965
2024-04-26 15:37:51 -06:00
Josh Cummings d88f2e5133 Merge branch '5.8.x' into 6.1.x
Closes gh-14957
2024-04-25 16:08:47 -06:00
Josh Cummings c35e107744 Add ProxyRestriction Validator
Closes gh-14931
2024-04-25 16:04:37 -06:00
Josh Cummings 3f7d9e389d Update to OAuth2 OIDC SDK 9.43.4
Issue gh-14920
2024-04-23 08:23:50 -06:00
Josh Cummings 992243fc8b Update to Nimbus 9.37.3
Closes gh-14836
2024-04-23 08:23:27 -06:00
github-actions[bot] d0341bf893 Merge branch '5.8.x' into 6.1.x 2024-04-22 01:13:08 +00:00
dependabot[bot] 8271258618 Bump slackapi/slack-github-action from 1.25.0 to 1.26.0
Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.25.0 to 1.26.0.
- [Release notes](https://github.com/slackapi/slack-github-action/releases)
- [Commits](https://github.com/slackapi/slack-github-action/compare/v1.25.0...v1.26.0)

---
updated-dependencies:
- dependency-name: slackapi/slack-github-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-21 18:12:20 -07:00
Rob Winch 761fdd228d Merge branch '5.8.x' into 6.1.x 2024-04-19 14:24:58 -05:00
Rob Winch 1010d253a4 Merge branch '5.7.x' into 5.8.x 2024-04-19 14:20:16 -05:00
Rob Winch c8342fcfae Use antora-extensions 1.10.0 2024-04-19 14:16:02 -05:00
github-actions[bot] c97f710747 Merge branch '5.8.x' into 6.1.x 2024-04-18 00:03:05 +00:00
dependabot[bot] 2287d67106 Bump io.projectreactor.tools:blockhound
Bumps [io.projectreactor.tools:blockhound](https://github.com/reactor/BlockHound) from 1.0.8.RELEASE to 1.0.9.RELEASE.
- [Release notes](https://github.com/reactor/BlockHound/releases)
- [Commits](https://github.com/reactor/BlockHound/compare/1.0.8.RELEASE...1.0.9.RELEASE)

---
updated-dependencies:
- dependency-name: io.projectreactor.tools:blockhound
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-17 17:01:58 -07:00
dependabot[bot] da4af08362 Bump io.spring.gradle:spring-security-release-plugin from 1.0.2 to 1.0.3
Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.2 to 1.0.3.
- [Release notes](https://github.com/spring-io/spring-security-release-tools/releases)
- [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.2...v1.0.3)

---
updated-dependencies:
- dependency-name: io.spring.gradle:spring-security-release-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-17 17:00:41 -07:00
Josh Cummings 61df8e493d Merge branch '5.8.x' into 6.1.x 2024-04-17 17:00:24 -06:00
Josh Cummings 470e2c5c97 Address Build Issues
Issue gh-14837
2024-04-17 16:59:40 -06:00
Josh Cummings ade45771b2 Merge branch '5.8.x' into 6.1.x
Closes gh-14921
2024-04-17 16:44:50 -06:00
Josh Cummings 657760af5b Improve Logging
Closes gh-14837
2024-04-17 16:43:29 -06:00
github-actions[bot] 8a03482856 Next development version 2024-04-15 16:01:13 +00:00
github-actions[bot] 71a51db3a1 Next development version 2024-04-15 15:58:06 +00:00
github-actions[bot] 17873adf1f Release 5.8.12 2024-04-15 15:21:00 +00:00
github-actions[bot] 4bab573562 Release 6.1.9 2024-04-15 15:20:31 +00:00
dependabot[bot] c74f6bdac4 Bump org.slf4j:slf4j-api from 2.0.12 to 2.0.13
Bumps org.slf4j:slf4j-api from 2.0.12 to 2.0.13.

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-14 21:05:20 -07:00
dependabot[bot] a55c5c1d0d Bump org.springframework:spring-framework-bom from 6.0.18 to 6.0.19
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.0.18 to 6.0.19.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.0.18...v6.0.19)

---
updated-dependencies:
- dependency-name: org.springframework:spring-framework-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-11 20:38:19 -07:00
github-actions[bot] 8a7ae7a7f9 Merge branch '5.8.x' into 6.1.x 2024-04-12 03:27:23 +00:00
dependabot[bot] a608352689 Bump org.springframework:spring-framework-bom from 5.3.33 to 5.3.34
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 5.3.33 to 5.3.34.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.33...v5.3.34)

---
updated-dependencies:
- dependency-name: org.springframework:spring-framework-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-11 20:26:39 -07:00
github-actions[bot] 0c20b14542 Merge branch '5.8.x' into 6.1.x 2024-04-10 04:21:44 +00:00
dependabot[bot] c3dbbb2d01 Bump io.projectreactor:reactor-bom from 2020.0.42 to 2020.0.43
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2020.0.42 to 2020.0.43.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2020.0.42...2020.0.43)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-09 21:20:55 -07:00
github-actions[bot] d187ddb5c6 Merge branch '5.8.x' into 6.1.x 2024-04-10 04:05:49 +00:00
dependabot[bot] 9a5319d5a2 Bump io.projectreactor.netty:reactor-netty from 1.0.43 to 1.0.44
Bumps [io.projectreactor.netty:reactor-netty](https://github.com/reactor/reactor-netty) from 1.0.43 to 1.0.44.
- [Release notes](https://github.com/reactor/reactor-netty/releases)
- [Commits](https://github.com/reactor/reactor-netty/compare/v1.0.43...v1.0.44)

---
updated-dependencies:
- dependency-name: io.projectreactor.netty:reactor-netty
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-09 21:05:03 -07:00
dependabot[bot] 1fb00879f6 Bump io.projectreactor:reactor-bom from 2022.0.17 to 2022.0.18
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2022.0.17 to 2022.0.18.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2022.0.17...2022.0.18)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-09 20:55:24 -07:00
Marcus Hert Da Coregio 472c9f8275 Avoid initializing raw bean during runtime in native-images
Closes gh-14825
2024-04-08 11:11:23 -03:00
Josh Cummings ef00312991 Merge branch '5.8.x' into 6.1.x
Closes gh-14847
2024-04-04 16:55:52 -06:00
Josh Cummings 0af0751cfd Treat Map Method Parameter as Immutable
Closes gh-14802
2024-04-04 16:44:14 -06:00
Steve Riesenberg c2447ec257 Merge branch '5.8.x' into 6.1.x 2024-04-04 14:55:03 -05:00
Steve Riesenberg 39dbd24dcb Polish gh-14742 2024-04-04 14:51:19 -05:00
sheheryarumair 33ebd5405a Removed dataSource null validation
Fixed data source validation
2024-04-04 14:21:18 -05:00
github-actions[bot] 76a465a544 Bump Gradle Wrapper from 8.6 to 8.7 2024-04-02 10:23:00 -06:00
dependabot[bot] 5f1b9862cc Bump io.spring.ge.conventions from 0.0.15 to 0.0.16
Bumps [io.spring.ge.conventions](https://github.com/spring-io/gradle-enterprise-conventions) from 0.0.15 to 0.0.16.
- [Release notes](https://github.com/spring-io/gradle-enterprise-conventions/releases)
- [Commits](https://github.com/spring-io/gradle-enterprise-conventions/compare/v0.0.15...v0.0.16)

---
updated-dependencies:
- dependency-name: io.spring.ge.conventions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-28 20:47:51 -07:00
github-actions[bot] 6a66a5b74f Merge branch '5.8.x' into 6.1.x 2024-03-29 03:44:43 +00:00
dependabot[bot] 2d2c2d31fa Bump io.spring.ge.conventions from 0.0.15 to 0.0.16
Bumps [io.spring.ge.conventions](https://github.com/spring-io/gradle-enterprise-conventions) from 0.0.15 to 0.0.16.
- [Release notes](https://github.com/spring-io/gradle-enterprise-conventions/releases)
- [Commits](https://github.com/spring-io/gradle-enterprise-conventions/compare/v0.0.15...v0.0.16)

---
updated-dependencies:
- dependency-name: io.spring.ge.conventions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-28 20:43:52 -07:00
Steve Riesenberg 80845d0c9a Fix NPE in Kotlin docs example
Closes gh-14634
2024-03-26 12:18:06 -05:00
Steve Riesenberg ba575e8564 Add tests for invalid/missing token
Issue gh-14634
2024-03-26 12:18:06 -05:00
dependabot[bot] 79801134b6 Bump org-aspectj from 1.9.21.2 to 1.9.22
Bumps `org-aspectj` from 1.9.21.2 to 1.9.22.

Updates `org.aspectj:aspectjrt` from 1.9.21.2 to 1.9.22
- [Release notes](https://github.com/eclipse/org.aspectj/releases)
- [Commits](https://github.com/eclipse/org.aspectj/commits)

Updates `org.aspectj:aspectjweaver` from 1.9.21.2 to 1.9.22
- [Release notes](https://github.com/eclipse/org.aspectj/releases)
- [Commits](https://github.com/eclipse/org.aspectj/commits)

---
updated-dependencies:
- dependency-name: org.aspectj:aspectjrt
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.aspectj:aspectjweaver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-24 20:45:35 -07:00
Josh Cummings 7162046144 Remove Reference to MethodInvocationResult
Closes gh-14794
2024-03-22 14:33:23 -06:00
Thomas Hagelberg ce9f1821b1 Improve logging in AuthenticationWebFilter
Closes #14091
2024-03-21 17:24:10 -06:00
dependabot[bot] 153ec5fbde Bump io.spring.gradle:spring-security-release-plugin from 1.0.1 to 1.0.2
Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/spring-io/spring-security-release-tools/releases)
- [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: io.spring.gradle:spring-security-release-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-20 20:36:41 -07:00
Marcus Hert Da Coregio b58018dc0f Merge branch '5.8.x' into 6.1.x 2024-03-18 09:27:48 -03:00
Marcus Hert Da Coregio 6c9efc2f09 Merge branch '5.7.x' into 5.8.x 2024-03-18 09:27:41 -03:00
github-actions[bot] 55be9eabd4 Next development version 2024-03-18 12:24:28 +00:00
github-actions[bot] 1a163dca37 Next development version 2024-03-18 11:47:59 +00:00
github-actions[bot] 1b0c4d68da Next development version 2024-03-18 11:38:53 +00:00
github-actions[bot] b38b495630 Release 5.7.12 2024-03-18 11:10:08 +00:00
github-actions[bot] c8a0601e6a Release 5.8.11 2024-03-18 11:10:03 +00:00
github-actions[bot] f226490be3 Release 6.1.8 2024-03-18 11:09:37 +00:00
Marcus Hert Da Coregio f84c4ea583 Merge branch '5.8.x' into 6.1.x
Closes gh-14665
2024-03-18 06:42:43 -03:00
Marcus Hert Da Coregio 2c9dc08e43 Merge branch '5.7.x' into 5.8.x
Closes gh-14664
2024-03-18 06:40:34 -03:00
Marcus Hert Da Coregio 5a7f12f1a9 Check for null Authentication
Closes gh-14715
2024-03-18 06:39:08 -03:00
dependabot[bot] 8d6ede27d1 Bump org.springframework:spring-framework-bom from 6.0.17 to 6.0.18
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.0.17 to 6.0.18.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.0.17...v6.0.18)

---
updated-dependencies:
- dependency-name: org.springframework:spring-framework-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-14 21:09:25 -07:00
github-actions[bot] 747b806d37 Merge branch '5.8.x' into 6.1.x 2024-03-15 04:08:29 +00:00
dependabot[bot] 3b355a0278 Bump org.springframework:spring-framework-bom from 5.3.32 to 5.3.33
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 5.3.32 to 5.3.33.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.32...v5.3.33)

---
updated-dependencies:
- dependency-name: org.springframework:spring-framework-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-14 21:07:46 -07:00
Marcus Hert Da Coregio 82e3061120 Merge branch '5.8.x' into 6.1.x 2024-03-14 15:12:51 -03:00
Marcus Hert Da Coregio a6d362fa18 Make trigger-dependabot-auto-merge-forward.yml run on push
Issue gh-14721
2024-03-14 15:12:14 -03:00
Marcus Hert Da Coregio dcfee957b5 Merge branch '5.8.x' into 6.1.x 2024-03-14 14:45:41 -03:00
Marcus Hert Da Coregio 37984c2e11 Add GH_TOKEN to set-milestone
Issue gh-14721
2024-03-14 14:45:36 -03:00
Marcus Hert Da Coregio d17a533e86 Merge branch '5.8.x' into 6.1.x 2024-03-14 14:42:39 -03:00
Marcus Hert Da Coregio b3a43d6154 Use token only for auto merge
Issue gh-14721
2024-03-14 14:42:33 -03:00
Marcus Hert Da Coregio 712595b3a3 Merge branch '5.8.x' into 6.1.x 2024-03-14 14:33:16 -03:00
Marcus Hert Da Coregio a87fc4ea8a Use pull_request_target for merge-dependabot-pr.yml
Issue gh-14721
2024-03-14 14:33:00 -03:00
Marcus Hert Da Coregio 85d7e9ab55 Merge branch '5.8.x' into 6.1.x 2024-03-14 09:23:49 -03:00
Marcus Hert Da Coregio e7bff4240a Use GH_ACTIONS_REPO_TOKEN for merge-dependabot-pr.yml
Issue gh-14721
2024-03-14 09:23:31 -03:00
dependabot[bot] 9794952153 Bump org-aspectj from 1.9.21.1 to 1.9.21.2
Bumps `org-aspectj` from 1.9.21.1 to 1.9.21.2.

Updates `org.aspectj:aspectjrt` from 1.9.21.1 to 1.9.21.2
- [Release notes](https://github.com/eclipse/org.aspectj/releases)
- [Commits](https://github.com/eclipse/org.aspectj/commits)

Updates `org.aspectj:aspectjweaver` from 1.9.21.1 to 1.9.21.2
- [Release notes](https://github.com/eclipse/org.aspectj/releases)
- [Commits](https://github.com/eclipse/org.aspectj/commits)

---
updated-dependencies:
- dependency-name: org.aspectj:aspectjrt
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.aspectj:aspectjweaver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 13:07:47 +00:00
github-actions[bot] 4b30acd1e0 Merge branch '5.8.x' into 6.1.x 2024-03-13 10:21:25 +00:00
dependabot[bot] 4e6b8e4d29 Bump io.projectreactor:reactor-bom from 2020.0.41 to 2020.0.42
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2020.0.41 to 2020.0.42.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2020.0.41...2020.0.42)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 04:24:14 +00:00
dependabot[bot] e550c48180 Bump io.projectreactor.netty:reactor-netty from 1.0.41 to 1.0.43
Bumps [io.projectreactor.netty:reactor-netty](https://github.com/reactor/reactor-netty) from 1.0.41 to 1.0.43.
- [Release notes](https://github.com/reactor/reactor-netty/releases)
- [Commits](https://github.com/reactor/reactor-netty/compare/v1.0.41...v1.0.43)

---
updated-dependencies:
- dependency-name: io.projectreactor.netty:reactor-netty
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 04:11:01 +00:00
dependabot[bot] 6d5f87e631 Bump io.projectreactor:reactor-bom from 2022.0.16 to 2022.0.17
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2022.0.16 to 2022.0.17.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2022.0.16...2022.0.17)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 03:52:55 +00:00
Marcus Hert Da Coregio 2202632cad Merge branch '5.8.x' into 6.1.x 2024-03-12 10:26:37 -03:00
Marcus Hert Da Coregio a3c06d98ca Trigger Dependabot Workflow when PR is merged
Issue gh-14721
2024-03-12 10:26:17 -03:00
Marcus Hert Da Coregio 8fe0303bad Merge branch '5.8.x' into 6.1.x
Closes gh-14722
2024-03-12 10:18:33 -03:00
Marcus Hert Da Coregio 8f42c86a57 Use AuthorizationInterceptorsOrder for Post Authorize Method Interceptors
Closes gh-14720
2024-03-12 10:17:45 -03:00
Marcus Hert Da Coregio a4a4c813d4 Merge branch '5.8.x' into 6.1.x 2024-03-11 09:26:11 -03:00
Marcus Hert Da Coregio 5dae6da15a Remove branch filter
Issue gh-14535
2024-03-11 09:25:58 -03:00
dependabot[bot] 6955c7aaea Bump jakarta.xml.bind:jakarta.xml.bind-api from 4.0.1 to 4.0.2
Bumps [jakarta.xml.bind:jakarta.xml.bind-api](https://github.com/jakartaee/jaxb-api) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/jakartaee/jaxb-api/releases)
- [Commits](https://github.com/jakartaee/jaxb-api/compare/4.0.1...4.0.2)

---
updated-dependencies:
- dependency-name: jakarta.xml.bind:jakarta.xml.bind-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-08 03:17:54 +00:00
Josh Cummings 0ab9ad774d Merge branch '5.8.x' into 6.1.x
Closes gh-14681
2024-03-04 15:42:35 -07:00
Josh Cummings e1c4177cd8 Fix ServerLogoutHandler Order in Docs
Closes gh-14379
2024-03-04 15:42:09 -07:00
Marcus Hert Da Coregio 7f34ef7951 Merge branch '5.8.x' into 6.1.x 2024-02-29 10:53:20 -03:00
Marcus Hert Da Coregio c2e97d7661 Ignore dependabot branches on trigger auto merge 2024-02-29 10:52:44 -03:00
dependabot[bot] 7e9f421a77 Bump io.mockk:mockk from 1.13.9 to 1.13.10
Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.9 to 1.13.10.
- [Release notes](https://github.com/mockk/mockk/releases)
- [Commits](https://github.com/mockk/mockk/compare/1.13.9...1.13.10)

---
updated-dependencies:
- dependency-name: io.mockk:mockk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-29 03:46:49 +00:00
Josh Cummings ddd5d2e9cd Fix Observability Typo
Closes gh-14651
2024-02-26 11:09:57 -07:00
Josh Cummings b20d05724f Merge branch '5.8.x' into 6.1.x 2024-02-26 10:07:09 -07:00
Josh Cummings 27cd9fa86c Don't Use Deprecated Class
Issue gh-14628
2024-02-26 10:06:59 -07:00
Josh Cummings 94a66f7a26 Change Structure101 Repository URL
Issug gh-14639
2024-02-26 10:03:09 -07:00
Josh Cummings 7f106f0419 Merge branch '5.8.x' into 6.1.x 2024-02-22 13:20:29 -07:00
Christian Becker 5f80468de3 Updated copyright date 2024-02-22 13:19:05 -07:00
Christian Becker 2f762fefe1 Allow tab in HTTP header values.
Closes gh-14573
2024-02-22 13:19:05 -07:00
Josh Cummings 2fdd541ea5 Merge branch '5.8.x' into 6.1.x
Closes gh-14647
2024-02-22 12:15:00 -07:00
DingHao 45c37c4454 Remove duplicate setSecurityContextHolderStrategy
Closes gh-14592
2024-02-22 12:14:35 -07:00
Josh Cummings 89246998c4 Move Cas Class
Closes gh-14627
2024-02-20 17:16:37 -07:00
Josh Cummings e8c93fdc98 Move Saml Class
Closes gh-14628
2024-02-20 17:15:41 -07:00
Josh Cummings 008296cce2 Exclude Deprecated Classes
Closes gh-14630
2024-02-20 15:58:55 -07:00
Josh Cummings 238bc9733a Remove stray projects 2024-02-20 15:57:46 -07:00
Josh Cummings d80fade8b1 Merge branch '5.8.x' into 6.1.x
Closes gh-14638
2024-02-20 15:55:48 -07:00
Josh Cummings 0c70f358d5 Update to Structure101 7.0.24375
Closes gh-14629
2024-02-20 15:43:58 -07:00
Marcus Hert Da Coregio 748c723bba Merge branch '5.8.x' into 6.1.x 2024-02-16 16:40:36 -03:00
github-actions[bot] 2bd2aa9a75 Next development version 2024-02-16 19:31:04 +00:00
github-actions[bot] 7d38686e09 Next development version 2024-02-16 19:29:53 +00:00
github-actions[bot] 8b9beb0e1f Release 5.8.10 2024-02-16 18:47:27 +00:00
github-actions[bot] dd5bfc0b31 Release 6.1.7 2024-02-16 18:46:45 +00:00
60 changed files with 903 additions and 849 deletions
@@ -1,23 +0,0 @@
name: Clean build artifacts
on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
permissions:
contents: read
jobs:
main:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
permissions:
contents: none
steps:
- name: Delete artifacts in cron job
env:
GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: |
echo "Running clean build artifacts logic"
output=$(curl -X GET -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts | grep '"id"' | cut -d : -f2 | sed 's/,*$//g')
echo Output is $output
for id in $output; do curl -X DELETE -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts/$id; done;
@@ -1,130 +0,0 @@
name: CI
on:
push:
branches-ignore:
- "dependabot/**"
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
env:
GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }}
GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
permissions:
contents: read
jobs:
build:
name: Build
uses: spring-io/spring-security-release-tools/.github/workflows/build.yml@v1
strategy:
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 17 ]
with:
runs-on: ${{ matrix.os }}
java-version: ${{ matrix.jdk }}
distribution: temurin
secrets: inherit
test:
name: Test Against Snapshots
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@v1
strategy:
matrix:
java-version: [ 17 ]
with:
java-version: ${{ matrix.java-version }}
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PspringFrameworkVersion=6.0.+ -PreactorVersion=2022.0.+ -PspringDataVersion=2022.0.+ --stacktrace
secrets: inherit
check-samples:
name: Check Samples
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'spring-projects' }}
steps:
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: 17
distribution: temurin
- name: Check samples project
env:
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
SAMPLES_DIR: ../spring-security-samples
run: |
# Extract version from gradle.properties
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
# Extract samplesBranch from gradle.properties
samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}')
./gradlew publishMavenJavaPublicationToLocalRepository
./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$samples_branch" -PcloneOutputDirectory="$SAMPLES_DIR"
./gradlew --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$version" :runAllTests
check-tangles:
name: Check for Package Tangles
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'spring-projects' }}
steps:
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: 17
distribution: temurin
- name: Check for package tangles
env:
STRUCTURE101_LICENSEID: ${{ secrets.STRUCTURE101_LICENSEID }}
run: |
./gradlew check s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace
deploy-artifacts:
name: Deploy Artifacts
needs: [ build, test, check-samples, check-tangles ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@v1
with:
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
secrets: inherit
deploy-docs:
name: Deploy Docs
needs: [ build, test, check-samples, check-tangles ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-docs.yml@v1
with:
should-deploy-docs: ${{ needs.build.outputs.should-deploy-artifacts }}
secrets: inherit
deploy-schema:
name: Deploy Schema
needs: [ build, test, check-samples, check-tangles ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@v1
with:
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
secrets: inherit
perform-release:
name: Perform Release
needs: [ deploy-artifacts, deploy-docs, deploy-schema ]
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@v1
with:
should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }}
project-version: ${{ needs.deploy-artifacts.outputs.project-version }}
milestone-repo-url: https://repo.spring.io/artifactory/milestone
release-repo-url: https://repo1.maven.org/maven2
artifact-path: org/springframework/security/spring-security-core
slack-announcing-id: spring-security-announcing
secrets: inherit
notify_result:
name: Check for failures
needs: [ perform-release ]
if: failure()
runs-on: ubuntu-latest
permissions:
actions: read
steps:
- name: Send Slack message
# Workaround while waiting for Gamesight/slack-workflow-status#38 to be fixed
# See https://github.com/Gamesight/slack-workflow-status/issues/38
uses: sjohnr/slack-workflow-status@v1-beta
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#spring-security-ci'
name: 'CI Notifier'
-33
View File
@@ -1,33 +0,0 @@
name: Deploy Docs
on:
push:
branches-ignore:
- "gh-pages"
- "dependabot/**"
tags: '**'
repository_dispatch:
types: request-build-reference # legacy
#schedule:
#- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch:
permissions: read-all
jobs:
build:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: docs-build
fetch-depth: 1
- name: Dispatch (partial build)
if: github.ref_type == 'branch'
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
- name: Dispatch (full build)
if: github.ref_type == 'tag'
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD)
-13
View File
@@ -1,13 +0,0 @@
name: Merge Dependabot PR
on:
pull_request:
run-name: Merge Dependabot PR ${{ github.ref_name }}
jobs:
merge-dependabot-pr:
permissions: write-all
uses: spring-io/spring-github-workflows/.github/workflows/spring-merge-dependabot-pr.yml@1e8b0587a1f4f01697f9753fa3339c3e0d30f396
with:
mergeArguments: '--auto --rebase'
@@ -1,40 +0,0 @@
name: Check Milestone
on:
milestone:
types: [created, opened, edited]
env:
DUE_ON: ${{ github.event.milestone.due_on }}
TITLE: ${{ github.event.milestone.title }}
permissions:
contents: read
jobs:
spring-releasetrain-checks:
name: Check DueOn is on a Release Date
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
permissions:
contents: none
steps:
- name: Print Milestone Being Checked
run: echo "Validating DueOn '$DUE_ON' for milestone '$TITLE'"
- name: Validate DueOn
if: env.DUE_ON != ''
run: |
export TOOL_VERSION=0.1.1
wget "https://repo.maven.apache.org/maven2/io/spring/releasetrain/spring-release-train-tools/$TOOL_VERSION/spring-release-train-tools-$TOOL_VERSION.jar"
java -cp "spring-release-train-tools-$TOOL_VERSION.jar" io.spring.releasetrain.CheckMilestoneDueOnMain --dueOn "$DUE_ON" --expectedDayOfWeek MONDAY --expectedMondayCount 3
notify_result:
name: Check for failures
needs: [spring-releasetrain-checks]
if: failure()
runs-on: ubuntu-latest
permissions:
actions: read
steps:
- name: Send Slack message
uses: Gamesight/slack-workflow-status@v1.3.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#spring-security-ci'
name: 'CI Notifier'
-26
View File
@@ -1,26 +0,0 @@
name: PR Build
on: pull_request
env:
GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }}
GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
permissions:
contents: read
jobs:
build:
name: Build
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew clean build --continue --scan
-24
View File
@@ -1,24 +0,0 @@
name: Release Scheduler
on:
schedule:
- cron: '15 15 * * MON' # Every Monday at 3:15pm UTC
workflow_dispatch:
permissions: read-all
jobs:
dispatch_scheduled_releases:
name: Dispatch scheduled releases
if: github.repository_owner == 'spring-projects'
strategy:
matrix:
# List of active maintenance branches.
branch: [ main, 6.0.x, 5.8.x, 5.7.x ]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Dispatch
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run update-scheduled-release-version.yml -r ${{ matrix.branch }}
@@ -1,22 +0,0 @@
name: Trigger Dependabot Auto Merge Forward
on:
push:
branches:
- '*.x'
permissions: read-all
jobs:
trigger-worflow:
name: Trigger Workflow
runs-on: ubuntu-latest
if: ${{ github.event.commits[0].author.username == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }}
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
- id: trigger
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run dependabot-auto-merge-forward.yml -r main
@@ -1,13 +0,0 @@
name: Update Scheduled Release Version
on:
workflow_dispatch: # Manual trigger only. Triggered by release-scheduler.yml on main.
permissions:
contents: read
jobs:
update-scheduled-release-version:
name: Update Scheduled Release Version
uses: spring-io/spring-security-release-tools/.github/workflows/update-scheduled-release-version.yml@v1
secrets: inherit
+2
View File
@@ -28,3 +28,5 @@ s101plugin.state
!.idea/checkstyle-idea.xml
!.idea/externalDependencies.xml
node_modules
+207 -220
View File
@@ -1,54 +1,236 @@
= Release Process
The release process for Spring Security is partially automated. The following table outlines which steps are automated and which are manual. Follow the links to read about each step.
The release process for Spring Security is entirely automated via the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc[Spring Security Release Plugin] and https://github.com/spring-io/spring-security-release-tools/tree/main/.github/workflows[reusable workflows].
The following table outlines the steps that are taken by the automation.
[cols="1,1"]
WARNING: The `5.8.x` branch does not have all of the improvements from the `6.x.x` branches. See "Status (5.8.x)" for which steps are still manual.
In case of a failure, you can follow the links below to read about each step, which includes instructions for performing the step manually if applicable.
See <<frequently-asked-questions,FAQ>> for troubleshooting tips.
[cols="1,1,1"]
|===
| Step | Status
| Step | Status (5.8.x) | Status (6.0.x+)
| <<update-dependencies>>
| :x: manual
| :white_check_mark: automated
| :white_check_mark: automated
| <<check-all-issues-are-closed>>
| :white_check_mark: automated (scheduled release will abort if any issues are open)
| :white_check_mark: automated
| :white_check_mark: automated
| <<update-release-version>>
| :white_check_mark: automated
| <<update-antora-version>>
| :white_check_mark: automated
| <<build-locally>>
| :x: manual (when updating dependencies)
| <<push-release-commit>>
| :white_check_mark: automated
| <<announce-release-on-slack>>
| :white_check_mark: automated
| <<tag-release>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<update-to-next-development-version>>
| <<push-release-commit>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<build-locally>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<update-release-notes-on-github>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<update-version-on-project-page>>
| :x: manual
| <<update-release-notes-on-github>>
| :white_check_mark: automated
| <<close-create-milestone,Close milestone>>
| :x: manual (move issues to new milestone before release)
| :x: manual
| :white_check_mark: automated
| <<announce-release-on-slack>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<update-to-next-development-version>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<close-create-milestone,Create milestone>>
| :white_check_mark: automated (if not already created)
| :white_check_mark: automated
| :white_check_mark: automated
| <<announce-release-on-other-channels>>
| :x: manual
| :x: manual
|===
[#update-dependencies]
== Update dependencies
Dependency versions are managed in the file xref:./gradle/libs.versions.toml[libs.versions.toml] and are automatically updated by xref:./.github/dependabot.yml[dependabot].
[#check-all-issues-are-closed]
== Check all issues are closed
The first step of a release is to check if there are any open issues remaining in a milestone.
NOTE: A scheduled release will not proceed if there are any open issues.
TIP: If you need to prevent a release from occurring automatically, the easiest way to block a release is to add an unresolved issue to the milestone.
The https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#checkMilestoneHasNoOpenIssues[`checkMilestoneHasOpenIssues`] command will check if there are any open issues for the release.
Before running the command manually, replace the following values:
* `<next-version>` - Replace with the title of the milestone you are releasing now (i.e. 5.5.0-RC1)
* `<github-personal-access-token>` - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`. This is optional since you are unlikely to reach the rate limit for such a simple check.
[source,bash]
----
./gradlew checkMilestoneHasOpenIssues -PnextVersion=<next-version> -PgitHubAccessToken=<github-personal-access-token>
----
Alternatively, you can manually check using the https://github.com/spring-projects/spring-security/milestones[milestones] page.
[#update-release-version]
== Update release version
If all issues for the release are <<check-all-issues-are-closed,closed>>, the version number is automatically updated using the milestone title.
When performing this step manually, update the version number in `gradle.properties` for the release (for example `5.5.0`) and commit the change using the message "Release x.y.z".
[#tag-release]
== Tag release
The release will automatically be tagged using the milestone title.
It is not required to tag manually.
However, you can perform this step manually by running the following command:
[source,bash]
----
git tag 5.5.0
----
[#push-release-commit]
== Push release commit
During a scheduled release, the release commit will automatically be pushed to trigger a build.
If performing this step manually, you can push the commit and tag and GitHub actions will build and deploy the artifacts with the following command:
[source,bash]
----
git push --atomic origin main 5.5.0
----
The build will automatically wait for artifacts to be released to Maven Central.
You can get notified manually when uploading is complete by running the following:
[source,bash]
----
./scripts/release/wait-for-done.sh 5.5.0
----
[#build-locally]
== Build
All checks will automatically be performed by the build prior to uploading the artifacts to Maven Central.
If something goes wrong, you can run the build locally using:
[source,bash]
----
./gradlew check
----
[#update-release-notes-on-github]
== Update release notes on GitHub
Once the release has been uploaded to Maven Central, release notes will automatically be generated and a GitHub release will be created.
To do this manually, you can use the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#generateChangelog[`generateChangelog`] command to generate the release notes by replacing:
* `<next-version>` - Replace with the milestone you are releasing now (i.e. 5.5.0)
[source,bash]
----
./gradlew generateChangelog -PnextVersion=<next-version>
----
Then copy the release notes to your clipboard (your mileage may vary with the following command):
[source,bash]
----
cat build/changelog/release-notes.md | xclip -selection clipboard
----
Finally, create the
https://github.com/spring-projects/spring-security/releases[release on
GitHub], associate it with the tag, and paste the generated notes.
Alternatively, you can run the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#createGitHubRelease[`createGitHubRelease`] command to perform these steps automatically, replacing:
* `<next-version>` - Replace with the milestone you are releasing now (i.e. 5.5.0)
* `<branch>` - The name of the branch to be tagged (if the release commit has not already been tagged)
* `<github-personal-access-token>` - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `write:org`
[source,bash]
----
./gradlew createGitHubRelease -PnextVersion=<next-version> -Pbranch=<branch> -PcreateRelease=true -PgitHubAccessToken=<github-personal-access-token>
----
[#update-version-on-project-page]
== Update version on project page
The build will automatically update the project versions on https://spring.io/projects/spring-security#learn.
To do this manually, you can use the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#createSaganRelease[`createSaganRelease`] and https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#deleteSaganRelease[`deleteSaganRelease`] commands using the following parameters:
* `<next-version>` - Replace with the milestone you are releasing now (i.e. 5.5.0)
* `<previous-version>` - Replace with the previous release which will be removed from the listed versions (i.e. 5.5.0-RC1)
* `<github-personal-access-token>` - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `read:org` as https://spring.io/restdocs/index.html#authentication[documented for spring.io api]
[source,bash]
----
./gradlew createSaganRelease deleteSaganRelease -PnextVersion=<next-version> -PpreviousVersion=<previous-version> -PgitHubAccessToken=<github-personal-access-token>
----
Alternatively, you can log into Contentful and update the versions manually on the Spring Security project page.
[#close-create-milestone]
== Close / Create milestone
The release milestone will be automatically closed once the release is complete.
To proceed manually, perform the following steps:
1. Visit https://github.com/spring-projects/spring-security/milestones[GitHub
Milestones] and create a new milestone for the next release version
2. Move any open issues from the existing milestone you just released to the new milestone
3. Close the milestone for the release
NOTE: Remember that scheduled releases <<check-all-issues-are-closed,will not proceed>> if there are still open issues in the milestone.
[#announce-release-on-slack]
== Announce release on Slack
The release will automatically be announced on Slack.
If proceeding manually, announce the release on Slack in the channel https://pivotal.slack.com/messages/spring-release[#spring-release], including the keyword `+spring-security-announcing+` in the message.
Something like:
....
spring-security-announcing `5.5.0` is available now
....
[#update-to-next-development-version]
== Update to next development version
After the release is complete and artifacts have been uploaded to Maven Central, the build will automatically update to the next development version, commit and push.
If proceeding manually, update the version in `gradle.properties` to the next `+SNAPSHOT+` version with the commit message "Next development version" and then push.
[#announce-release-on-other-channels]
== Announce release on other channels
* Create a blog post on Contentful
* Tweet from https://twitter.com/springsecurity[@SpringSecurity]
[[frequently-asked-questions]]
== Frequently Asked Questions
*When should I update dependencies manually?* Dependencies should be updated at the latest the end of the week prior to the release. This is usually the Friday following the 2nd Monday of the month (counting from the first week with a Monday). When in doubt, check the https://github.com/spring-projects/spring-security/milestones[milestones] page for release due dates.
*When do scheduled releases occur?* Automated releases are scheduled to occur at *3:15 PM UTC* on the *3rd Monday of the month* (counting from the first week with a Monday).
@@ -59,9 +241,10 @@ The scheduled release process currently runs every Monday but only releases when
The automated release process occurs on the following branches:
* `main`
* `6.0.x`
* `6.2.x`
* `6.1.x`
* `6.0.x` (commercial only)
* `5.8.x`
* `5.7.x`
For each of the above branches, the automated process performs the following checks before proceeding with the release:
@@ -71,7 +254,7 @@ For each of the above branches, the automated process performs the following che
[IMPORTANT]
You should ensure all issues are closed or moved to another milestone prior to a scheduled release.
If the above checks pass, the version number is updated (in `gradle.properties` and `antora.yml`) and a commit is pushed to trigger the CI process.
If the above checks pass, the version number is updated (in `gradle.properties`) and a commit is pushed to trigger the CI process.
*How do I trigger a release manually?* You can trigger a release manually in two ways:
@@ -81,199 +264,3 @@ If the above checks pass, the version number is updated (in `gradle.properties`
*When should additional manual steps be performed?* All other automated steps listed above occur during the normal CI process. Additional manual steps can be performed at any time once the builds pass and releases are finished.
*What if something goes wrong?* If the normal CI process fails, you can retry by re-running the failed jobs with the "Re-run failed jobs" option in GitHub Actions. If changes are required, you should revert the "Release x.y.z" commit, delete the tag, and proceed manually.
[#update-dependencies]
== Update dependencies
Ensure you have no changes in your local repository.
Change to a new branch.
For example:
[source,bash]
----
$ git checkout -b 5.5.0-RC1-dependencies
----
Review the rules in build.gradle to ensure the rules make sense.
For example, we should not allow major version updates in a patch release.
Also ensure that all of the exclusions still make sense.
The following Gradle command will update your dependencies creating a commit for each dependency update.
The first invocation of the command will take quite a while (~20 minutes depending on internet speed) to run because it is indexing all the versions of all the dependencies.
[source,bash]
----
$ ./gradlew updateDependencies
----
Review the commits to ensure that the updated dependency versions make sense for this release. For example, we should not perform a major version update for a patch release.
[source,bash]
----
$ git log
----
If any of the versions dont make sense, update `build.gradle` to ensure that the version is excluded.
Run all the checks:
[source,bash]
----
$ ./gradlew check
----
If they dont work, you can run a git bisect to discover what broke the build.
Fix any commits that broke the build.
Check out the original brach:
[source,bash]
----
$ git checkout -
----
The following command will update the dependencies again but this time creating a ticket for each update and placing `Closes gh-<number>` in the commit. Replacing the following values:
* <github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`
* <next-version> - Replace with the title of the milestone you are releasing now (i.e. 5.5.0-RC1)
[source,bash]
----
$ ./gradlew updateDependencies -PupdateMode=GITHUB_ISSUE -PgitHubAccessToken=<github-personal-access-token> -PnextVersion=<next-version>
----
Apply any fixes from your previous branch that were necessary.
[#check-all-issues-are-closed]
== Check all issues are closed
The following command will check if there are any open issues for the ticket.
Before running the command, replace the following values:
* <github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`. This is optional since you are unlikely to reach the rate limit for such a simple check.
* <next-version> - Replace with the title of the milestone you are releasing now (i.e. 5.5.0-RC1)
[source,bash]
----
$ ./gradlew gitHubCheckMilestoneHasNoOpenIssues -PgitHubAccessToken=<github-personal-access-token> -PnextVersion=<next-version>
----
Alternatively, you can manually check using https://github.com/spring-projects/spring-security/milestones
[#update-release-version]
== Update release version
Update the version number in `gradle.properties` for the release, for example `5.5.0-M1`, `5.5.0-RC1`, `5.5.0`
[#update-antora-version]
== Update antora version
You will need to update the antora.yml version.
If you are unsure of what the values should be, the following task will instruct you what the expected values are:
[source,bash]
----
./gradlew :spring-security-docs:antoraCheckVersion
----
[#build-locally]
== Build locally
Run the build using
[source,bash]
----
$ ./gradlew check
----
[#push-release-commit]
== Push release commit
Push the commit and GitHub actions will build and deploy the artifacts
If you are pushing to Maven Central, then you can get notified when its uploaded by running the following:
[source,bash]
----
$ ./scripts/release/wait-for-done.sh 5.5.0
----
[#announce-release-on-slack]
== Announce release on Slack
* Announce via Slack on
https://pivotal.slack.com/messages/spring-release[#spring-release],
including the keyword `+spring-security-announcing+` in the message.
Something like:
....
spring-security-announcing 5.5.0 is available.
....
[#tag-release]
== Tag release
* Tag the release and then push the tag
....
git tag 5.4.0-RC1
git push origin 5.4.0-RC1
....
[#update-to-next-development-version]
== Update to next development version
* Update `gradle.properties` version to next `+SNAPSHOT+` version, update antora.yml, and then push
[#update-version-on-project-page]
== Update version on project page
The following command will update https://spring.io/projects/spring-security#learn with the new release version using the following parameters
<github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `read:org` as https://spring.io/restdocs/index.html#authentication[documented for spring.io api]
<next-version> - Replace with the milestone you are releasing now (i.e. 5.5.0-RC1)
<previous-version> - Replace with the previous release which will be removed from the listed versions (i.e. 5.5.0-M3)
[source,bash]
----
$ ./gradlew saganCreateRelease saganDeleteRelease -PgitHubAccessToken=<github-personal-access-token> -PnextVersion=<next-version> -PpreviousVersion=<previous-version>
----
[#update-release-notes-on-github]
== Update release notes on GitHub
Generate the Release Notes replacing:
* <next-version> - Replace with the milestone you are releasing now (i.e. 5.5.0-RC1)
----
$ ./gradlew generateChangelog -PnextVersion=<next-version>
----
* Copy the release notes to your clipboard (your mileage may vary with
the following command)
....
cat build/changelog/release-notes.md | xclip -selection clipboard
....
* Create the
https://github.com/spring-projects/spring-security/releases[release on
GitHub], associate it with the tag, and paste the generated notes
[#close-create-milestone]
== Close / Create milestone
* In
https://github.com/spring-projects/spring-security/milestones[GitHub
Milestones], create a new milestone for the next release version
* Move any open issues from the existing milestone you just released to
the new milestone
* Close the milestone for the release.
[#announce-release-on-other-channels]
== Announce release on other channels
* Create a https://spring.io/admin/blog[Blog]
* Tweet from [@SpringSecurity](https://twitter.com/springsecurity)
+5 -4
View File
@@ -37,7 +37,7 @@ springRelease {
weekOfMonth = 3
dayOfWeek = 1
referenceDocUrl = "https://docs.spring.io/spring-security/reference/{version}/index.html"
apiDocUrl = "https://docs.spring.io/spring-security/docs/{version}/api/"
apiDocUrl = "https://docs.spring.io/spring-security/site/docs/{version}/api/"
replaceSnapshotVersionInReferenceDocUrl = true
}
@@ -86,10 +86,10 @@ allprojects {
}
}
if (hasProperty('buildScan')) {
develocity {
buildScan {
termsOfServiceUrl = 'https://gradle.com/terms-of-service'
termsOfServiceAgree = 'yes'
termsOfUseUrl = 'https://gradle.com/help/legal-terms-of-use'
termsOfUseAgree = 'yes'
}
}
@@ -106,5 +106,6 @@ tasks.register('cloneRepository', IncludeRepoTask) {
}
s101 {
repository = 'https://structure101.com/binaries/latest'
configurationDirectory = project.file("etc/s101")
}
+11 -46
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 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,7 +17,6 @@
package s101;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -34,18 +33,11 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
@@ -71,6 +63,10 @@ public class S101Configurer {
private final Path licenseDirectory;
private final String repository;
private final String version;
private final Project project;
private final Logger logger;
@@ -90,6 +86,9 @@ public class S101Configurer {
throw new UncheckedIOException(ex);
}
this.licenseDirectory = new File(System.getProperty("user.home") + "/.Structure101/java").toPath();
S101PluginExtension extension = project.getExtensions().getByType(S101PluginExtension.class);
this.repository = extension.getRepository().get();
this.version = extension.getVersion().get();
}
public void license(String licenseId) {
@@ -129,25 +128,7 @@ public class S101Configurer {
public void configure(File installationDirectory, File configurationDirectory) {
deleteDirectory(configurationDirectory);
String version = computeVersionFromInstallation(installationDirectory);
configureProject(version, configurationDirectory);
}
private String computeVersionFromInstallation(File installationDirectory) {
File buildJar = new File(installationDirectory, "structure101-java-build.jar");
try (JarInputStream input = new JarInputStream(new FileInputStream(buildJar))) {
JarEntry entry;
while ((entry = input.getNextJarEntry()) != null) {
if (entry.getName().contains("structure101-build.properties")) {
Properties properties = new Properties();
properties.load(input);
return properties.getProperty("s101-build");
}
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
throw new IllegalStateException("Unable to determine Structure101 version");
configureProject(this.version, configurationDirectory);
}
private boolean deleteDirectory(File directoryToBeDeleted) {
@@ -161,24 +142,8 @@ public class S101Configurer {
}
private String installBuildTool(File installationDirectory, File configurationDirectory) {
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;
}
}
if (matcher == null) {
return null;
}
copyZipToFilesystem(source, installationDirectory, matcher.group(1) + matcher.group(2));
return matcher.group(2);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
copyZipToFilesystem(this.repository, installationDirectory, "structure101-build-java-all-" + this.version);
return this.version;
}
private void copyZipToFilesystem(String source, File destination, String name) {
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 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,7 +17,12 @@
package s101;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
@@ -25,6 +30,11 @@ import org.gradle.api.tasks.InputDirectory;
public class S101PluginExtension {
private final Property<String> licenseId;
private final Property<String> repository;
private final Property<String> version;
private final Property<File> installationDirectory;
private final Property<File> configurationDirectory;
private final Property<String> label;
@@ -65,6 +75,24 @@ public class S101PluginExtension {
this.label.set(label);
}
@Input
public Property<String> getRepository() {
return repository;
}
public void setRepository(String repository) {
this.repository.set(repository);
}
@Input
public Property<String> getVersion() {
return this.version;
}
public void setVersion(String version) {
this.version.set(version);
}
public S101PluginExtension(Project project) {
this.licenseId = project.getObjects().property(String.class);
if (project.hasProperty("s101.licenseId")) {
@@ -78,5 +106,31 @@ public class S101PluginExtension {
if (project.hasProperty("s101.label")) {
setLabel((String) project.findProperty("s101.label"));
}
this.repository = project.getObjects().property(String.class);
if (project.hasProperty("s101.repository")) {
setRepository((String) project.findProperty("s101.repository"));
} else {
setRepository("https://structure101.com/binaries/v6");
}
this.version = project.getObjects().property(String.class);
if (project.hasProperty("s101.version")) {
setVersion((String) project.findProperty("s101.version"));
} else {
try (final WebClient webClient = new WebClient()) {
HtmlPage page = webClient.getPage(getRepository().get());
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;
}
}
if (matcher != null) {
setVersion(matcher.group(2));
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
}
@@ -31,7 +31,6 @@ import org.springframework.security.authentication.AccountStatusUserDetailsCheck
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
@@ -0,0 +1,41 @@
/*
* Copyright 2011-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.cas.authentication;
import java.io.Serializable;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.Authentication;
/**
* In order for the {@link CasAuthenticationProvider} to provide the correct service url
* to authenticate the ticket, the returned value of {@link Authentication#getDetails()}
* should implement this interface when tickets can be sent to any URL rather than only
* {@link ServiceProperties#getService()}.
*
* @author Rob Winch
* @see org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource
*/
public interface ServiceAuthenticationDetails extends Serializable {
/**
* Gets the absolute service url (i.e. https://example.com/service/).
* @return the service url. Cannot be <code>null</code>.
*/
String getServiceUrl();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2023 the original author or authors.
* Copyright 2011-2024 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,22 +16,24 @@
package org.springframework.security.cas.web.authentication;
import java.io.Serializable;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.core.Authentication;
/**
* In order for the {@link CasAuthenticationProvider} to provide the correct service url
* to authenticate the ticket, the returned value of {@link Authentication#getDetails()}
* should implement this interface when tickets can be sent to any URL rather than only
* {@link ServiceProperties#getService()}.
* In order for the
* {@link org.springframework.security.cas.authentication.CasAuthenticationProvider} to
* provide the correct service url to authenticate the ticket, the returned value of
* {@link Authentication#getDetails()} should implement this interface when tickets can be
* sent to any URL rather than only {@link ServiceProperties#getService()}.
*
* @author Rob Winch
* @see ServiceAuthenticationDetailsSource
* @deprecated Please use
* org.springframework.security.cas.authentication.ServiceAuthenticationDetails
*/
public interface ServiceAuthenticationDetails extends Serializable {
@Deprecated
public interface ServiceAuthenticationDetails
extends org.springframework.security.cas.authentication.ServiceAuthenticationDetails {
/**
* Gets the absolute service url (i.e. https://example.com/service/).
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2024 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,11 +22,14 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.core.NativeDetector;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.util.Assert;
@@ -55,14 +58,13 @@ final class AutowireBeanFactoryObjectPostProcessor
}
@Override
@SuppressWarnings("unchecked")
public <T> T postProcess(T object) {
if (object == null) {
return null;
}
T result = null;
try {
result = (T) this.autowireBeanFactory.initializeBean(object, object.toString());
result = initializeBeanIfNeeded(object);
}
catch (RuntimeException ex) {
Class<?> type = object.getClass();
@@ -78,6 +80,36 @@ final class AutowireBeanFactoryObjectPostProcessor
return result;
}
/**
* Invokes {@link AutowireCapableBeanFactory#initializeBean(Object, String)} only if
* needed, i.e when the application is not a native image or the object is not a CGLIB
* proxy.
* @param object the object to initialize
* @param <T> the type of the object
* @return the initialized bean or an existing bean if the object is a CGLIB proxy and
* the application is a native image
* @see <a href=
* "https://github.com/spring-projects/spring-security/issues/14825">Issue
* gh-14825</a>
*/
@SuppressWarnings("unchecked")
private <T> T initializeBeanIfNeeded(T object) {
if (!NativeDetector.inNativeImage() || !AopUtils.isCglibProxy(object)) {
return (T) this.autowireBeanFactory.initializeBean(object, object.toString());
}
ObjectProvider<?> provider = this.autowireBeanFactory.getBeanProvider(object.getClass());
Object bean = provider.getIfUnique();
if (bean == null) {
String msg = """
Failed to resolve an unique bean (single or primary) of type [%s] from the BeanFactory.
Because the object is a CGLIB Proxy, a raw bean cannot be initialized during runtime in a native image.
"""
.formatted(object.getClass());
throw new IllegalStateException(msg);
}
return (T) bean;
}
@Override
public void afterSingletonsInstantiated() {
for (SmartInitializingSingleton singleton : this.smartSingletons) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -335,7 +335,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
LogoutFilter result = new LogoutFilter(getLogoutSuccessHandler(), handlers);
result.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
result.setLogoutRequestMatcher(getLogoutRequestMatcher(http));
result.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
result = postProcess(result);
return result;
}
@@ -23,11 +23,11 @@ import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.saml2.provider.service.metadata.OpenSamlMetadataResolver;
import org.springframework.security.saml2.provider.service.metadata.RequestMatcherMetadataResponseResolver;
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponseResolver;
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.web.Saml2MetadataFilter;
import org.springframework.security.saml2.provider.service.web.metadata.RequestMatcherMetadataResponseResolver;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2024 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,7 +42,7 @@ public class JdbcUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String dataSource = element.getAttribute(ATT_DATA_SOURCE);
if (dataSource != null) {
if (StringUtils.hasText(dataSource)) {
builder.addPropertyReference("dataSource", dataSource);
}
else {
@@ -41,8 +41,6 @@ public class PasswordEncoderParser {
public static final String ATT_HASH = "hash";
static final String ATT_BASE_64 = "base64";
static final String OPT_HASH_BCRYPT = "bcrypt";
private static final Map<String, Class<?>> ENCODER_CLASSES = Collections.singletonMap(OPT_HASH_BCRYPT,
@@ -62,19 +60,17 @@ public class PasswordEncoderParser {
return;
}
String hash = element.getAttribute(ATT_HASH);
boolean useBase64 = StringUtils.hasText(element.getAttribute(ATT_BASE_64))
&& Boolean.parseBoolean(element.getAttribute(ATT_BASE_64));
String ref = element.getAttribute(ATT_REF);
if (StringUtils.hasText(ref)) {
this.passwordEncoder = new RuntimeBeanReference(ref);
}
else {
this.passwordEncoder = createPasswordEncoderBeanDefinition(hash, useBase64);
this.passwordEncoder = createPasswordEncoderBeanDefinition(hash);
((RootBeanDefinition) this.passwordEncoder).setSource(parserContext.extractSource(element));
}
}
public static BeanDefinition createPasswordEncoderBeanDefinition(String hash, boolean useBase64) {
public static BeanDefinition createPasswordEncoderBeanDefinition(String hash) {
Class<?> beanClass = ENCODER_CLASSES.get(hash);
BeanDefinitionBuilder beanBldr = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
return beanBldr.getBeanDefinition();
@@ -98,7 +98,7 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
}
else if (StringUtils.hasText(hash)) {
authenticatorBuilder.addPropertyValue("passwordEncoder",
PasswordEncoderParser.createPasswordEncoderBeanDefinition(hash, false));
PasswordEncoderParser.createPasswordEncoderBeanDefinition(hash));
}
}
authenticatorBuilder.addConstructorArgValue(contextSource);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2024 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,9 +16,13 @@
package org.springframework.security.config.annotation.configuration;
import java.lang.reflect.Modifier;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
@@ -31,13 +35,16 @@ import org.springframework.context.EnvironmentAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.NativeDetector;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.web.context.ServletContextAware;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatException;
import static org.mockito.ArgumentMatchers.isNotNull;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -132,6 +139,59 @@ public class AutowireBeanFactoryObjectPostProcessorTests {
assertThat(bean.doStuff()).isEqualTo("null");
}
@Test
void postProcessWhenObjectIsCgLibProxyAndInNativeImageThenUseExistingBean() {
try (var detector = Mockito.mockStatic(NativeDetector.class)) {
given(NativeDetector.inNativeImage()).willReturn(true);
ProxyFactory proxyFactory = new ProxyFactory(new MyClass());
proxyFactory.setProxyTargetClass(!Modifier.isFinal(MyClass.class.getModifiers()));
MyClass myClass = (MyClass) proxyFactory.getProxy();
this.spring.register(Config.class, myClass.getClass()).autowire();
this.spring.getContext().getBean(myClass.getClass()).setIdentifier("0000");
MyClass postProcessed = this.objectObjectPostProcessor.postProcess(myClass);
assertThat(postProcessed.getIdentifier()).isEqualTo("0000");
}
}
@Test
void postProcessWhenObjectIsCgLibProxyAndInNativeImageAndBeanDoesNotExistsThenIllegalStateException() {
try (var detector = Mockito.mockStatic(NativeDetector.class)) {
given(NativeDetector.inNativeImage()).willReturn(true);
ProxyFactory proxyFactory = new ProxyFactory(new MyClass());
proxyFactory.setProxyTargetClass(!Modifier.isFinal(MyClass.class.getModifiers()));
MyClass myClass = (MyClass) proxyFactory.getProxy();
this.spring.register(Config.class).autowire();
assertThatException().isThrownBy(() -> this.objectObjectPostProcessor.postProcess(myClass))
.havingRootCause()
.isInstanceOf(IllegalStateException.class)
.withMessage(
"""
Failed to resolve an unique bean (single or primary) of type [class org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessorTests$MyClass$$SpringCGLIB$$0] from the BeanFactory.
Because the object is a CGLIB Proxy, a raw bean cannot be initialized during runtime in a native image.
""");
}
}
static class MyClass {
private String identifier = "1234";
String getIdentifier() {
return this.identifier;
}
void setIdentifier(String identifier) {
this.identifier = identifier;
}
}
@Configuration
static class Config {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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,7 +19,10 @@ package org.springframework.security.config.authentication;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Element;
import org.xml.sax.SAXParseException;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.CachingUserDetailsService;
import org.springframework.security.authentication.ProviderManager;
@@ -33,6 +36,7 @@ import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.util.FieldUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock;
/**
@@ -160,6 +164,38 @@ public class JdbcUserServiceBeanDefinitionParserTests {
assertThat(AuthorityUtils.authorityListToSet(rod.getAuthorities())).contains("PREFIX_ROLE_SUPERVISOR");
}
@Test
public void testEmptyDataSourceRef() {
// @formatter:off
String xml = "<authentication-manager>"
+ " <authentication-provider>"
+ " <jdbc-user-service data-source-ref=''/>"
+ " </authentication-provider>"
+ "</authentication-manager>";
assertThatExceptionOfType(BeanDefinitionParsingException.class)
.isThrownBy(() -> setContext(xml))
.withFailMessage("Expected exception due to empty data-source-ref")
.withMessageContaining("data-source-ref is required for jdbc-user-service");
// @formatter:on
}
@Test
public void testMissingDataSourceRef() {
// @formatter:off
String xml = "<authentication-manager>"
+ " <authentication-provider>"
+ " <jdbc-user-service/>"
+ " </authentication-provider>"
+ "</authentication-manager>";
assertThatExceptionOfType(XmlBeanDefinitionStoreException.class)
.isThrownBy(() -> setContext(xml))
.withFailMessage("Expected exception due to missing data-source-ref")
.havingRootCause()
.isInstanceOf(SAXParseException.class)
.withMessageContaining("Attribute 'data-source-ref' must appear on element 'jdbc-user-service'");
// @formatter:on
}
private void setContext(String context) {
this.appContext = new InMemoryXmlApplicationContext(context);
}
@@ -20,10 +20,13 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.web.servlet.MockMvc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -65,4 +68,15 @@ public class PasswordEncoderParserTests {
// @formatter:on
}
@Test
void testCreatePasswordEncoderBeanDefinition() throws Exception {
String hash = "bcrypt";
Class<?> expectedBeanClass = BCryptPasswordEncoder.class;
BeanDefinition beanDefinition = PasswordEncoderParser.createPasswordEncoderBeanDefinition(hash);
Class<?> actualBeanClass = Class.forName(beanDefinition.getBeanClassName());
assertThat(actualBeanClass).isEqualTo(expectedBeanClass);
}
}
@@ -61,8 +61,7 @@ public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
private boolean isFullyAuthenticated(Authentication authentication) {
return (!this.authenticationTrustResolver.isAnonymous(authentication)
&& !this.authenticationTrustResolver.isRememberMe(authentication));
return this.authenticationTrustResolver.isFullyAuthenticated(authentication);
}
public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {
@@ -21,8 +21,6 @@ import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationConvention;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.authorization.method.MethodInvocationResult;
/**
* An {@link ObservationConvention} for translating authorizations into {@link KeyValues}.
*
@@ -85,10 +83,10 @@ public final class AuthorizationObservationConvention
if (context.getObject() instanceof MethodInvocation) {
return "method";
}
if (context.getObject() instanceof MethodInvocationResult) {
String className = context.getObject().getClass().getSimpleName();
if (className.contains("Method")) {
return "method";
}
String className = context.getObject().getClass().getSimpleName();
if (className.contains("Request")) {
return "request";
}
@@ -93,7 +93,7 @@ public final class AuthorizationManagerAfterMethodInterceptor
PostAuthorizeAuthorizationManager authorizationManager) {
AuthorizationManagerAfterMethodInterceptor interceptor = new AuthorizationManagerAfterMethodInterceptor(
AuthorizationMethodPointcuts.forAnnotations(PostAuthorize.class), authorizationManager);
interceptor.setOrder(500);
interceptor.setOrder(AuthorizationInterceptorsOrder.POST_AUTHORIZE.getOrder());
return interceptor;
}
@@ -107,7 +107,7 @@ public final class AuthorizationManagerAfterMethodInterceptor
AuthorizationManager<MethodInvocationResult> authorizationManager) {
AuthorizationManagerAfterMethodInterceptor interceptor = new AuthorizationManagerAfterMethodInterceptor(
AuthorizationMethodPointcuts.forAnnotations(PostAuthorize.class), authorizationManager);
interceptor.setOrder(500);
interceptor.setOrder(AuthorizationInterceptorsOrder.POST_AUTHORIZE.getOrder());
return interceptor;
}
@@ -59,6 +59,7 @@ public class AuthenticatedVoterTests {
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createAnonymous(), null, def));
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createRememberMe(), null, def));
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createFullyAuthenticated(), null, def));
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(null, null, def));
}
@Test
@@ -68,6 +69,7 @@ public class AuthenticatedVoterTests {
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(createAnonymous(), null, def));
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(createRememberMe(), null, def));
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createFullyAuthenticated(), null, def));
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(null, null, def));
}
@Test
@@ -77,6 +79,7 @@ public class AuthenticatedVoterTests {
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(createAnonymous(), null, def));
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createRememberMe(), null, def));
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createFullyAuthenticated(), null, def));
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(null, null, def));
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@@ -129,6 +129,10 @@ public class DelegatingPasswordEncoder implements PasswordEncoder {
private static final String DEFAULT_ID_SUFFIX = "}";
public static final String NO_PASSWORD_ENCODER_MAPPED = "There is no PasswordEncoder mapped for the id \"%s\"";
public static final String NO_PASSWORD_ENCODER_PREFIX = "You have entered a password with no PasswordEncoder. If that is your intent, it should be prefixed with `{noop}`.";
private final String idPrefix;
private final String idSuffix;
@@ -286,7 +290,10 @@ public class DelegatingPasswordEncoder implements PasswordEncoder {
@Override
public boolean matches(CharSequence rawPassword, String prefixEncodedPassword) {
String id = extractId(prefixEncodedPassword);
throw new IllegalArgumentException("There is no PasswordEncoder mapped for the id \"" + id + "\"");
if (id != null && !id.isEmpty()) {
throw new IllegalArgumentException(String.format(NO_PASSWORD_ENCODER_MAPPED, id));
}
throw new IllegalArgumentException(NO_PASSWORD_ENCODER_PREFIX);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@@ -43,6 +43,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
@ExtendWith(MockitoExtension.class)
public class DelegatingPasswordEncoderTests {
public static final String NO_PASSWORD_ENCODER = "You have entered a password with no PasswordEncoder. If that is your intent, it should be prefixed with `{noop}`.";
@Mock
private PasswordEncoder bcrypt;
@@ -201,7 +203,7 @@ public class DelegatingPasswordEncoderTests {
public void matchesWhenNoClosingPrefixStringThenIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "{bcrypt" + this.rawPassword))
.withMessage("There is no PasswordEncoder mapped for the id \"null\"");
.withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop);
}
@@ -209,7 +211,7 @@ public class DelegatingPasswordEncoderTests {
public void matchesWhenNoStartingPrefixStringThenFalse() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "bcrypt}" + this.rawPassword))
.withMessage("There is no PasswordEncoder mapped for the id \"null\"");
.withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop);
}
@@ -217,7 +219,7 @@ public class DelegatingPasswordEncoderTests {
public void matchesWhenNoIdStringThenFalse() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "{}" + this.rawPassword))
.withMessage("There is no PasswordEncoder mapped for the id \"\"");
.withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop);
}
@@ -226,7 +228,7 @@ public class DelegatingPasswordEncoderTests {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "invalid" + this.bcryptEncodedPassword))
.isInstanceOf(IllegalArgumentException.class)
.withMessage("There is no PasswordEncoder mapped for the id \"null\"");
.withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop);
}
@@ -236,7 +238,7 @@ public class DelegatingPasswordEncoderTests {
DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder(this.bcryptId, this.delegates);
assertThatIllegalArgumentException()
.isThrownBy(() -> passwordEncoder.matches(this.rawPassword, this.rawPassword))
.withMessage("There is no PasswordEncoder mapped for the id \"null\"");
.withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop);
}
@@ -289,4 +291,14 @@ public class DelegatingPasswordEncoderTests {
verifyNoMoreInteractions(this.bcrypt);
}
@Test
void matchesShouldThrowIllegalArgumentExceptionWhenNoPasswordEncoderIsMappedForTheId() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches("rawPassword", "prefixEncodedPassword"))
.isInstanceOf(IllegalArgumentException.class)
.withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop);
}
}
+37
View File
@@ -0,0 +1,37 @@
antora:
extensions:
- require: '@springio/antora-extensions'
root_component_name: 'security'
site:
title: Spring Security
url: https://docs.spring.io/spring-security/reference
robots: allow
git:
ensure_git_suffix: false
content:
sources:
- url: https://github.com/spring-projects/spring-security
branches: [main, '5.{{6..9},{1..9}+({0..9})}.x', '6.+({0..9}).x']
tags: ['5.{{6..9},{1..9}+({0..9})}.{0..99}?(-RC+({0..9}))', '6.+({0..9}).+({0..9})?(-{RC,M}*)','!(5.6.{0..10}*)', '!(5.7.{0..8}*)', '!(5.8.{0..3}?({-RC,-M}+({0..9})))','!(6.0.{0..3}*)','!(6.1.0*)']
start_path: docs
asciidoc:
attributes:
page-stackoverflow-url: https://stackoverflow.com/tags/spring-security
page-related-doc-categories: security
page-related-doc-projects: framework,graphql
hide-uri-scheme: '@'
tabs-sync-option: '@'
extensions:
- '@asciidoctor/tabs'
- '@springio/asciidoctor-extensions'
urls:
latest_version_segment_strategy: redirect:to
latest_version_segment: ''
redirect_facility: httpd
ui:
bundle:
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.15/ui-bundle.zip
snapshot: true
runtime:
log:
failure_level: warn
@@ -20,7 +20,7 @@ Java::
@Bean
SecurityWebFilterChain http(ServerHttpSecurity http) throws Exception {
DelegatingServerLogoutHandler logoutHandler = new DelegatingServerLogoutHandler(
new WebSessionServerLogoutHandler(), new SecurityContextServerLogoutHandler()
new SecurityContextServerLogoutHandler(), new WebSessionServerLogoutHandler()
);
http
@@ -38,7 +38,7 @@ Kotlin::
@Bean
fun http(http: ServerHttpSecurity): SecurityWebFilterChain {
val customLogoutHandler = DelegatingServerLogoutHandler(
WebSessionServerLogoutHandler(), SecurityContextServerLogoutHandler()
SecurityContextServerLogoutHandler(), WebSessionServerLogoutHandler()
)
return http {
@@ -105,6 +105,7 @@ Java::
[source,java,role="primary"]
----
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults("MYPREFIX_");
}
@@ -113,7 +114,8 @@ static GrantedAuthorityDefaults grantedAuthorityDefaults() {
[TIP]
====
We expose `GrantedAuthorityDefaults` using a `static` method to ensure that Spring publishes it before it initializes Spring Security's method security `@Configuration` classes
We expose `GrantedAuthorityDefaults` using a `static` method to ensure that Spring publishes it before it initializes Spring Security's method security `@Configuration` classes.
Since the `GrantedAuthorityDefaults` bean is part of internal workings of Spring Security, we should also expose it as an infrastructural bean effectively avoiding some warnings related to bean post-processing (see https://github.com/spring-projects/spring-security/issues/14751[gh-14751]).
====
[[jc-reactive-method-security-custom-authorization-manager]]
@@ -38,7 +38,7 @@ public class MyApplication {
@Bean
ObservationRegistryCustomizer<ObservationRegistry> addTextHandler() {
return (registry) -> registry.observationConfig().observationHandler(new ObservationTextHandler());
return (registry) -> registry.observationConfig().observationHandler(new ObservationTextPublisher());
}
public static void main(String[] args) {
@@ -67,7 +67,7 @@ class MyApplication {
@Bean
fun addTextHandler(): ObservationRegistryCustomizer<ObservationRegistry> {
return registry: ObservationRegistry -> registry.observationConfig()
.observationHandler(ObservationTextHandler());
.observationHandler(ObservationTextPublisher());
}
fun main(args: Array<String>) {
@@ -129,7 +129,7 @@ public class MyApplication {
@Bean
ObservationRegistry<ObservationRegistry> observationRegistry() {
ObservationRegistry registry = ObservationRegistry.create();
registry.observationConfig().observationHandler(new ObservationTextHandler());
registry.observationConfig().observationHandler(new ObservationTextPublisher());
return registry;
}
@@ -159,7 +159,7 @@ class MyApplication {
@Bean
fun observationRegistry(): ObservationRegistry<ObservationRegistry> {
ObservationRegistry registry = ObservationRegistry.create()
registry.observationConfig().observationHandler(ObservationTextHandler())
registry.observationConfig().observationHandler(ObservationTextPublisher())
return registry
}
@@ -449,7 +449,7 @@ In Spring Security this is done by saving the `HttpServletRequest` using a <<req
The `HttpServletRequest` is saved in the {security-api-url}org/springframework/security/web/savedrequest/RequestCache.html[`RequestCache`].
When the user successfully authenticates, the `RequestCache` is used to replay the original request.
The <<requestcacheawarefilter,`RequestCacheAwareFilter`>> is what uses the `RequestCache` to save the `HttpServletRequest`.
The <<requestcacheawarefilter,`RequestCacheAwareFilter`>> uses the `RequestCache` to get the saved `HttpServletRequest` after the user authenticates, while the `ExceptionTranslationFilter` uses the `RequestCache` to save the `HttpServletRequest` after it detects `AuthenticationException`, before redirecting the user to the login endpoint.
By default, an `HttpSessionRequestCache` is used.
The code below demonstrates how to customize the `RequestCache` implementation that is used to check the `HttpSession` for a saved request if the parameter named `continue` is present.
@@ -517,7 +517,7 @@ XML::
[[requestcacheawarefilter]]
=== RequestCacheAwareFilter
The {security-api-url}org/springframework/security/web/savedrequest/RequestCacheAwareFilter.html[`RequestCacheAwareFilter`] uses the <<requestcache,`RequestCache`>> to save the `HttpServletRequest`.
The {security-api-url}org/springframework/security/web/savedrequest/RequestCacheAwareFilter.html[`RequestCacheAwareFilter`] uses the <<requestcache,`RequestCache`>> to replay the original request.
[[servlet-logging]]
== Logging
@@ -876,7 +876,7 @@ class SpaCsrfTokenRequestHandler : CsrfTokenRequestAttributeHandler() {
delegate.handle(request, response, csrfToken)
}
override fun resolveCsrfTokenValue(request: HttpServletRequest, csrfToken: CsrfToken): String {
override fun resolveCsrfTokenValue(request: HttpServletRequest, csrfToken: CsrfToken): String? {
/*
* If the request contains a request header, use CsrfTokenRequestAttributeHandler
* to resolve the CsrfToken. This applies when a single-page application includes
@@ -1221,6 +1221,24 @@ public class CsrfTests {
.andExpect(header().string(HttpHeaders.LOCATION, "/"));
}
@Test
public void loginWhenInvalidCsrfTokenThenForbidden() throws Exception {
this.mockMvc.perform(post("/login").with(csrf().useInvalidToken())
.accept(MediaType.TEXT_HTML)
.param("username", "user")
.param("password", "password"))
.andExpect(status().isForbidden());
}
@Test
public void loginWhenMissingCsrfTokenThenForbidden() throws Exception {
this.mockMvc.perform(post("/login")
.accept(MediaType.TEXT_HTML)
.param("username", "user")
.param("password", "password"))
.andExpect(status().isForbidden());
}
@Test
@WithMockUser
public void logoutWhenValidCsrfTokenThenSuccess() throws Exception {
@@ -1264,6 +1282,24 @@ class CsrfTests {
.andExpect(header().string(HttpHeaders.LOCATION, "/"))
}
@Test
fun loginWhenInvalidCsrfTokenThenForbidden() {
mockMvc.perform(post("/login").with(csrf().useInvalidToken())
.accept(MediaType.TEXT_HTML)
.param("username", "user")
.param("password", "password"))
.andExpect(status().isForbidden)
}
@Test
fun loginWhenMissingCsrfTokenThenForbidden() {
mockMvc.perform(post("/login")
.accept(MediaType.TEXT_HTML)
.param("username", "user")
.param("password", "password"))
.andExpect(status().isForbidden)
}
@Test
@WithMockUser
@Throws(Exception::class)
@@ -131,7 +131,7 @@ public class DefaultSecurityConfig {
InMemoryUserDetailsManager inMemoryUserDetailsManager() { <2>
String generatedPassword = // ...;
return new InMemoryUserDetailsManager(User.withUsername("user")
.password(generatedPassword).roles("ROLE_USER").build());
.password(generatedPassword).roles("USER").build());
}
@Bean
@@ -38,7 +38,7 @@ public class MyApplication {
@Bean
ObservationRegistryCustomizer<ObservationRegistry> addTextHandler() {
return (registry) -> registry.observationConfig().observationHandler(new ObservationTextHandler());
return (registry) -> registry.observationConfig().observationHandler(new ObservationTextPublisher());
}
public static void main(String[] args) {
@@ -67,7 +67,7 @@ class MyApplication {
@Bean
fun addTextHandler(): ObservationRegistryCustomizer<ObservationRegistry> {
return registry: ObservationRegistry -> registry.observationConfig()
.observationHandler(ObservationTextHandler());
.observationHandler(ObservationTextPublisher());
}
fun main(args: Array<String>) {
@@ -134,7 +134,7 @@ public class MyApplication {
@Bean
ObservationRegistry<ObservationRegistry> observationRegistry() {
ObservationRegistry registry = ObservationRegistry.create();
registry.observationConfig().observationHandler(new ObservationTextHandler());
registry.observationConfig().observationHandler(new ObservationTextPublisher());
return registry;
}
@@ -164,7 +164,7 @@ class MyApplication {
@Bean
fun observationRegistry(): ObservationRegistry<ObservationRegistry> {
ObservationRegistry registry = ObservationRegistry.create()
registry.observationConfig().observationHandler(ObservationTextHandler())
registry.observationConfig().observationHandler(ObservationTextPublisher())
return registry
}
+10
View File
@@ -0,0 +1,10 @@
{
"dependencies": {
"antora": "3.2.0-alpha.4",
"@antora/atlas-extension": "1.0.0-alpha.2",
"@antora/collector-extension": "1.0.0-alpha.3",
"@asciidoctor/tabs": "1.0.0-beta.6",
"@springio/antora-extensions": "1.10.0",
"@springio/asciidoctor-extensions": "1.0.0-alpha.10"
}
}
+4 -7
View File
@@ -8,14 +8,11 @@ apply plugin: 'io.spring.convention.docs'
apply plugin: 'java'
antora {
playbook = 'cached-antora-playbook.yml'
playbookProvider {
repository = 'spring-projects/spring-security'
branch = 'docs-build'
path = 'lib/antora/templates/per-branch-antora-playbook.yml'
checkLocalBranch = true
}
options = [clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
environment = [
'BUILD_REFNAME': 'HEAD',
'BUILD_VERSION': project.version,
]
}
tasks.named("generateAntoraYml") {
+1 -4
View File
@@ -10,7 +10,7 @@
<property name="relative-to" value="const(THIS_FILE)/../.." />
<property name="action-set-mod" value="1" />
<property name="detail-mode" value="true" />
<property name="hide-deprecated" value="false" />
<property name="hide-deprecated" value="true" />
<property name="resolve-name-clashes" value="true" />
<property name="project-excluded" />
<property name="show-needs-to-compile" value="false" />
@@ -29,11 +29,8 @@
<classpathentry kind="lib" path="oauth2/oauth2-core/build/classes/java/main" module="spring-security-oauth2-core" />
<classpathentry kind="lib" path="oauth2/oauth2-jose/build/classes/java/main" module="spring-security-oauth2-jose" />
<classpathentry kind="lib" path="oauth2/oauth2-resource-server/build/classes/java/main" module="spring-security-oauth2-resource-server" />
<classpathentry kind="lib" path="remoting/build/classes/java/main" module="spring-security-remoting" />
<classpathentry kind="lib" path="rsocket/build/classes/java/main" module="spring-security-rsocket" />
<classpathentry kind="lib" path="saml2/saml2-service-provider/build/classes/java/main" module="spring-security-saml2-service-provider" />
<classpathentry kind="lib" path="saml2/saml2-service-provider/build/classes/java/opensaml3Main" module="spring-security-saml2-service-provider" />
<classpathentry kind="lib" path="saml2/saml2-service-provider/build/classes/java/opensaml4Main" module="spring-security-saml2-service-provider" />
<classpathentry kind="lib" path="taglibs/build/classes/java/main" module="spring-security-taglibs" />
<classpathentry kind="lib" path="test/build/classes/java/main" module="spring-security-test" />
<classpathentry kind="lib" path="web/build/classes/java/main" module="spring-security-web" />
+1 -1
View File
@@ -1,5 +1,5 @@
springBootVersion=3.1.1
version=6.1.7-SNAPSHOT
version=6.1.10-SNAPSHOT
samplesBranch=6.1.x
org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError
org.gradle.parallel=true
+11 -11
View File
@@ -6,36 +6,36 @@ io-spring-nohttp = "0.0.11"
jakarta-websocket = "2.1.1"
org-apache-directory-server = "1.5.5"
org-apache-maven-resolver = "1.8.2"
org-aspectj = "1.9.21.1"
org-aspectj = "1.9.22.1"
org-bouncycastle = "1.70"
org-eclipse-jetty = "11.0.20"
org-eclipse-jetty = "11.0.21"
org-jetbrains-kotlin = "1.8.22"
org-jetbrains-kotlinx = "1.6.4"
org-mockito = "4.8.1"
org-opensaml = "4.1.1"
org-springframework = "6.0.17"
org-springframework = "6.0.20"
[libraries]
ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.4.14"
com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.14.3"
com-google-inject-guice = "com.google.inject:guice:3.0"
com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0"
com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.24.4"
com-nimbusds-oauth2-oidc-sdk = "com.nimbusds:oauth2-oidc-sdk:9.43.3"
com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3"
com-nimbusds-oauth2-oidc-sdk = "com.nimbusds:oauth2-oidc-sdk:9.43.4"
com-squareup-okhttp3-mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "com-squareup-okhttp3" }
com-squareup-okhttp3-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "com-squareup-okhttp3" }
com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11"
commons-collections = "commons-collections:commons-collections:3.2.2"
io-freefair-gradle-aspectj-plugin = "io.freefair.gradle:aspectj-plugin:6.6.3"
io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.10.13"
io-mockk = "io.mockk:mockk:1.13.9"
io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2022.0.16"
io-mockk = "io.mockk:mockk:1.13.11"
io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2022.0.19"
io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" }
io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" }
io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" }
io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" }
io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" }
io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.1"
io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.3"
jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1"
jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1"
jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0"
@@ -44,7 +44,7 @@ jakarta-servlet-jsp-jakarta-servlet-jsp-api = "jakarta.servlet.jsp:jakarta.servl
jakarta-servlet-jsp-jstl-jakarta-servlet-jsp-jstl-api = "jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:3.0.0"
jakarta-websocket-jakarta-websocket-api = { module = "jakarta.websocket:jakarta.websocket-api", version.ref = "jakarta-websocket" }
jakarta-websocket-jakarta-websocket-client-api = { module = "jakarta.websocket:jakarta.websocket-client-api", version.ref = "jakarta-websocket" }
jakarta-xml-bind-jakarta-xml-bind-api = "jakarta.xml.bind:jakarta.xml.bind-api:4.0.1"
jakarta-xml-bind-jakarta-xml-bind-api = "jakarta.xml.bind:jakarta.xml.bind-api:4.0.2"
ldapsdk = "ldapsdk:ldapsdk:4.1"
net-sourceforge-htmlunit = "net.sourceforge.htmlunit:htmlunit:2.66.0"
org-apache-directory-server-apacheds-core = { module = "org.apache.directory.server:apacheds-core", version.ref = "org-apache-directory-server" }
@@ -83,7 +83,7 @@ org-seleniumhq-selenium-selenium-java = "org.seleniumhq.selenium:selenium-java:3
org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-support:3.141.59"
org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.1"
org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36"
org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.12"
org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.13"
org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2022.0.12"
org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.0.6"
org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" }
@@ -97,7 +97,7 @@ org-apache-commons-commons-io = "org.apache.commons:commons-io:1.3.2"
io-github-gradle-nexus-publish-plugin = "io.github.gradle-nexus:publish-plugin:1.1.0"
org-gretty-gretty = "org.gretty:gretty:4.0.3"
com-github-ben-manes-gradle-versions-plugin = "com.github.ben-manes:gradle-versions-plugin:0.38.0"
com-github-spullara-mustache-java-compiler = "com.github.spullara.mustache.java:compiler:0.9.11"
com-github-spullara-mustache-java-compiler = "com.github.spullara.mustache.java:compiler:0.9.13"
org-hidetake-gradle-ssh-plugin = "org.hidetake:gradle-ssh-plugin:2.10.1"
org-jfrog-buildinfo-build-info-extractor-gradle = "org.jfrog.buildinfo:build-info-extractor-gradle:4.29.4"
org-sonarsource-scanner-gradle-sonarqube-gradle-plugin = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1"
Binary file not shown.
+2 -2
View File
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
@@ -179,16 +180,17 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
}
private OAuth2AuthenticatedPrincipal convertClaimsSet(Map<String, Object> claims) {
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
Map<String, Object> converted = new LinkedHashMap<>(claims);
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
if (v instanceof String) {
return Collections.singletonList(v);
}
return v;
});
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
// RFC-7662 page 7 directs users to RFC-7519 for defining the values of these
// issuer fields.
@@ -208,11 +210,11 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
// may be awkward to debug, we do not want to manipulate this value. Previous
// versions of Spring Security
// would *only* allow valid URLs, which is not what we wish to achieve here.
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
Collection<GrantedAuthority> authorities = new ArrayList<>();
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
if (v instanceof String) {
Collection<String> scopes = Arrays.asList(((String) v).split(" "));
for (String scope : scopes) {
@@ -222,7 +224,7 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
}
return v;
});
return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities);
return new OAuth2IntrospectionAuthenticatedPrincipal(converted, authorities);
}
}
@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import reactor.core.publisher.Mono;
@@ -136,16 +137,17 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
}
private OAuth2AuthenticatedPrincipal convertClaimsSet(Map<String, Object> claims) {
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
Map<String, Object> converted = new LinkedHashMap<>(claims);
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
if (v instanceof String) {
return Collections.singletonList(v);
}
return v;
});
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
// RFC-7662 page 7 directs users to RFC-7519 for defining the values of these
// issuer fields.
@@ -165,11 +167,11 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
// may be awkward to debug, we do not want to manipulate this value. Previous
// versions of Spring Security
// would *only* allow valid URLs, which is not what we wish to achieve here.
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
Collection<GrantedAuthority> authorities = new ArrayList<>();
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
if (v instanceof String) {
Collection<String> scopes = Arrays.asList(((String) v).split(" "));
for (String scope : scopes) {
@@ -179,7 +181,7 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
}
return v;
});
return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities);
return new OAuth2IntrospectionAuthenticatedPrincipal(converted, authorities);
}
private OAuth2IntrospectionException onError(Throwable ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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,6 +54,7 @@ import org.opensaml.saml.saml2.assertion.SubjectConfirmationValidator;
import org.opensaml.saml.saml2.assertion.impl.AudienceRestrictionConditionValidator;
import org.opensaml.saml.saml2.assertion.impl.BearerSubjectConfirmationValidator;
import org.opensaml.saml.saml2.assertion.impl.DelegationRestrictionConditionValidator;
import org.opensaml.saml.saml2.assertion.impl.ProxyRestrictionConditionValidator;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.core.AttributeStatement;
@@ -804,6 +805,7 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv
return ValidationResult.VALID;
}
});
conditions.add(new ProxyRestrictionConditionValidator());
subjects.add(new BearerSubjectConfirmationValidator() {
@Override
protected ValidationResult validateAddress(SubjectConfirmation confirmation, Assertion assertion,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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,25 +16,9 @@
package org.springframework.security.saml2.provider.service.metadata;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.saml2.Saml2Exception;
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.web.RelyingPartyRegistrationPlaceholderResolvers;
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationPlaceholderResolvers.UriResolver;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
* An implementation of {@link Saml2MetadataResponseResolver} that identifies which
@@ -42,140 +26,23 @@ import org.springframework.util.Assert;
*
* @author Josh Cummings
* @since 6.1
* @deprecated Please use
* {@link org.springframework.security.saml2.provider.service.web.metadata.RequestMatcherMetadataResponseResolver}
*/
public final class RequestMatcherMetadataResponseResolver implements Saml2MetadataResponseResolver {
private static final String DEFAULT_METADATA_FILENAME = "saml-{registrationId}-metadata.xml";
private RequestMatcher matcher = new OrRequestMatcher(
new AntPathRequestMatcher("/saml2/service-provider-metadata/{registrationId}"),
new AntPathRequestMatcher("/saml2/metadata/{registrationId}"),
new AntPathRequestMatcher("/saml2/metadata"));
private String filename = DEFAULT_METADATA_FILENAME;
private final RelyingPartyRegistrationRepository registrations;
private final Saml2MetadataResolver metadata;
@Deprecated
public final class RequestMatcherMetadataResponseResolver extends
org.springframework.security.saml2.provider.service.web.metadata.RequestMatcherMetadataResponseResolver {
/**
* Construct a {@link RequestMatcherMetadataResponseResolver}
* Construct a
* {@link org.springframework.security.saml2.provider.service.web.metadata.RequestMatcherMetadataResponseResolver}
* @param registrations the source for relying party metadata
* @param metadata the strategy for converting {@link RelyingPartyRegistration}s into
* metadata
*/
public RequestMatcherMetadataResponseResolver(RelyingPartyRegistrationRepository registrations,
Saml2MetadataResolver metadata) {
Assert.notNull(registrations, "relyingPartyRegistrationRepository cannot be null");
Assert.notNull(metadata, "saml2MetadataResolver cannot be null");
this.registrations = registrations;
this.metadata = metadata;
}
/**
* Construct and serialize a relying party's SAML 2.0 metadata based on the given
* {@link HttpServletRequest}. Uses the configured {@link RequestMatcher} to identify
* the metadata request, including looking for any indicated {@code registrationId}.
*
* <p>
* If a {@code registrationId} is found in the request, it will attempt to use that,
* erroring if no {@link RelyingPartyRegistration} is found.
*
* <p>
* If no {@code registrationId} is found in the request, it will attempt to show all
* {@link RelyingPartyRegistration}s in an {@code <md:EntitiesDescriptor>}. To
* exercise this functionality, the provided
* {@link RelyingPartyRegistrationRepository} needs to implement {@link Iterable}.
* @param request the HTTP request
* @return a {@link Saml2MetadataResponse} instance
* @throws Saml2Exception if the {@link RequestMatcher} specifies a non-existent
* {@code registrationId}
*/
@Override
public Saml2MetadataResponse resolve(HttpServletRequest request) {
RequestMatcher.MatchResult result = this.matcher.matcher(request);
if (!result.isMatch()) {
return null;
}
String registrationId = result.getVariables().get("registrationId");
Saml2MetadataResponse response = responseByRegistrationId(request, registrationId);
if (response != null) {
return response;
}
if (this.registrations instanceof Iterable<?>) {
Iterable<RelyingPartyRegistration> registrations = (Iterable<RelyingPartyRegistration>) this.registrations;
return responseByIterable(request, registrations);
}
return null;
}
private Saml2MetadataResponse responseByRegistrationId(HttpServletRequest request, String registrationId) {
if (registrationId == null) {
return null;
}
RelyingPartyRegistration registration = this.registrations.findByRegistrationId(registrationId);
if (registration == null) {
throw new Saml2Exception("registration not found");
}
return responseByIterable(request, Collections.singleton(registration));
}
private Saml2MetadataResponse responseByIterable(HttpServletRequest request,
Iterable<RelyingPartyRegistration> registrations) {
Map<String, RelyingPartyRegistration> results = new LinkedHashMap<>();
for (RelyingPartyRegistration registration : registrations) {
UriResolver uriResolver = RelyingPartyRegistrationPlaceholderResolvers.uriResolver(request, registration);
String entityId = uriResolver.resolve(registration.getEntityId());
results.computeIfAbsent(entityId, (e) -> {
String ssoLocation = uriResolver.resolve(registration.getAssertionConsumerServiceLocation());
String sloLocation = uriResolver.resolve(registration.getSingleLogoutServiceLocation());
String sloResponseLocation = uriResolver.resolve(registration.getSingleLogoutServiceResponseLocation());
return registration.mutate()
.entityId(entityId)
.assertionConsumerServiceLocation(ssoLocation)
.singleLogoutServiceLocation(sloLocation)
.singleLogoutServiceResponseLocation(sloResponseLocation)
.build();
});
}
String metadata = this.metadata.resolve(results.values());
String value = (results.size() == 1) ? results.values().iterator().next().getRegistrationId()
: UUID.randomUUID().toString();
String fileName = this.filename.replace("{registrationId}", value);
try {
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
return new Saml2MetadataResponse(metadata, encodedFileName);
}
catch (UnsupportedEncodingException ex) {
throw new Saml2Exception(ex);
}
}
/**
* Use this {@link RequestMatcher} to identity which requests to generate metadata
* for. By default, matches {@code /saml2/metadata},
* {@code /saml2/metadata/{registrationId}}, {@code /saml2/service-provider-metadata},
* and {@code /saml2/service-provider-metadata/{registrationId}}
* @param requestMatcher the {@link RequestMatcher} to use
*/
public void setRequestMatcher(RequestMatcher requestMatcher) {
Assert.notNull(requestMatcher, "requestMatcher cannot be empty");
this.matcher = requestMatcher;
}
/**
* Sets the metadata filename template. If it contains the {@code {registrationId}}
* placeholder, it will be resolved as a random UUID if there are multiple
* {@link RelyingPartyRegistration}s. Otherwise, it will be replaced by the
* {@link RelyingPartyRegistration}'s id.
*
* <p>
* The default value is {@code saml-{registrationId}-metadata.xml}
* @param metadataFilename metadata filename, must contain a {registrationId}
*/
public void setMetadataFilename(String metadataFilename) {
Assert.hasText(metadataFilename, "metadataFilename cannot be empty");
this.filename = metadataFilename;
super(registrations, metadata);
}
}
@@ -0,0 +1,185 @@
/*
* Copyright 2002-2024 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.saml2.provider.service.web.metadata;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.saml2.Saml2Exception;
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResolver;
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponse;
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponseResolver;
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.web.RelyingPartyRegistrationPlaceholderResolvers;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
* An implementation of {@link Saml2MetadataResponseResolver} that identifies which
* {@link RelyingPartyRegistration}s to use with a {@link RequestMatcher}
*
* @author Josh Cummings
* @since 6.1
*/
public class RequestMatcherMetadataResponseResolver implements Saml2MetadataResponseResolver {
private static final String DEFAULT_METADATA_FILENAME = "saml-{registrationId}-metadata.xml";
private RequestMatcher matcher = new OrRequestMatcher(
new AntPathRequestMatcher("/saml2/service-provider-metadata/{registrationId}"),
new AntPathRequestMatcher("/saml2/metadata/{registrationId}"),
new AntPathRequestMatcher("/saml2/metadata"));
private String filename = DEFAULT_METADATA_FILENAME;
private final RelyingPartyRegistrationRepository registrations;
private final Saml2MetadataResolver metadata;
/**
* Construct a
* {@link org.springframework.security.saml2.provider.service.metadata.RequestMatcherMetadataResponseResolver}
* @param registrations the source for relying party metadata
* @param metadata the strategy for converting {@link RelyingPartyRegistration}s into
* metadata
*/
public RequestMatcherMetadataResponseResolver(RelyingPartyRegistrationRepository registrations,
Saml2MetadataResolver metadata) {
Assert.notNull(registrations, "relyingPartyRegistrationRepository cannot be null");
Assert.notNull(metadata, "saml2MetadataResolver cannot be null");
this.registrations = registrations;
this.metadata = metadata;
}
/**
* Construct and serialize a relying party's SAML 2.0 metadata based on the given
* {@link HttpServletRequest}. Uses the configured {@link RequestMatcher} to identify
* the metadata request, including looking for any indicated {@code registrationId}.
*
* <p>
* If a {@code registrationId} is found in the request, it will attempt to use that,
* erroring if no {@link RelyingPartyRegistration} is found.
*
* <p>
* If no {@code registrationId} is found in the request, it will attempt to show all
* {@link RelyingPartyRegistration}s in an {@code <md:EntitiesDescriptor>}. To
* exercise this functionality, the provided
* {@link RelyingPartyRegistrationRepository} needs to implement {@link Iterable}.
* @param request the HTTP request
* @return a {@link Saml2MetadataResponse} instance
* @throws Saml2Exception if the {@link RequestMatcher} specifies a non-existent
* {@code registrationId}
*/
@Override
public Saml2MetadataResponse resolve(HttpServletRequest request) {
RequestMatcher.MatchResult result = this.matcher.matcher(request);
if (!result.isMatch()) {
return null;
}
String registrationId = result.getVariables().get("registrationId");
Saml2MetadataResponse response = responseByRegistrationId(request, registrationId);
if (response != null) {
return response;
}
if (this.registrations instanceof Iterable<?>) {
Iterable<RelyingPartyRegistration> registrations = (Iterable<RelyingPartyRegistration>) this.registrations;
return responseByIterable(request, registrations);
}
return null;
}
private Saml2MetadataResponse responseByRegistrationId(HttpServletRequest request, String registrationId) {
if (registrationId == null) {
return null;
}
RelyingPartyRegistration registration = this.registrations.findByRegistrationId(registrationId);
if (registration == null) {
throw new Saml2Exception("registration not found");
}
return responseByIterable(request, Collections.singleton(registration));
}
private Saml2MetadataResponse responseByIterable(HttpServletRequest request,
Iterable<RelyingPartyRegistration> registrations) {
Map<String, RelyingPartyRegistration> results = new LinkedHashMap<>();
for (RelyingPartyRegistration registration : registrations) {
RelyingPartyRegistrationPlaceholderResolvers.UriResolver uriResolver = RelyingPartyRegistrationPlaceholderResolvers
.uriResolver(request, registration);
String entityId = uriResolver.resolve(registration.getEntityId());
results.computeIfAbsent(entityId, (e) -> {
String ssoLocation = uriResolver.resolve(registration.getAssertionConsumerServiceLocation());
String sloLocation = uriResolver.resolve(registration.getSingleLogoutServiceLocation());
String sloResponseLocation = uriResolver.resolve(registration.getSingleLogoutServiceResponseLocation());
return registration.mutate()
.entityId(entityId)
.assertionConsumerServiceLocation(ssoLocation)
.singleLogoutServiceLocation(sloLocation)
.singleLogoutServiceResponseLocation(sloResponseLocation)
.build();
});
}
String metadata = this.metadata.resolve(results.values());
String value = (results.size() == 1) ? results.values().iterator().next().getRegistrationId()
: UUID.randomUUID().toString();
String fileName = this.filename.replace("{registrationId}", value);
try {
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
return new Saml2MetadataResponse(metadata, encodedFileName);
}
catch (UnsupportedEncodingException ex) {
throw new Saml2Exception(ex);
}
}
/**
* Use this {@link RequestMatcher} to identity which requests to generate metadata
* for. By default, matches {@code /saml2/metadata},
* {@code /saml2/metadata/{registrationId}}, {@code /saml2/service-provider-metadata},
* and {@code /saml2/service-provider-metadata/{registrationId}}
* @param requestMatcher the {@link RequestMatcher} to use
*/
public void setRequestMatcher(RequestMatcher requestMatcher) {
Assert.notNull(requestMatcher, "requestMatcher cannot be empty");
this.matcher = requestMatcher;
}
/**
* Sets the metadata filename template. If it contains the {@code {registrationId}}
* placeholder, it will be resolved as a random UUID if there are multiple
* {@link RelyingPartyRegistration}s. Otherwise, it will be replaced by the
* {@link RelyingPartyRegistration}'s id.
*
* <p>
* The default value is {@code saml-{registrationId}-metadata.xml}
* @param metadataFilename metadata filename, must contain a {registrationId}
*/
public void setMetadataFilename(String metadataFilename) {
Assert.hasText(metadataFilename, "metadataFilename cannot be empty");
this.filename = metadataFilename;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -53,6 +53,7 @@ import org.opensaml.saml.saml2.core.EncryptedAttribute;
import org.opensaml.saml.saml2.core.EncryptedID;
import org.opensaml.saml.saml2.core.NameID;
import org.opensaml.saml.saml2.core.OneTimeUse;
import org.opensaml.saml.saml2.core.ProxyRestriction;
import org.opensaml.saml.saml2.core.Response;
import org.opensaml.saml.saml2.core.StatusCode;
import org.opensaml.saml.saml2.core.SubjectConfirmation;
@@ -61,6 +62,7 @@ import org.opensaml.saml.saml2.core.impl.AttributeBuilder;
import org.opensaml.saml.saml2.core.impl.EncryptedAssertionBuilder;
import org.opensaml.saml.saml2.core.impl.EncryptedIDBuilder;
import org.opensaml.saml.saml2.core.impl.NameIDBuilder;
import org.opensaml.saml.saml2.core.impl.ProxyRestrictionBuilder;
import org.opensaml.xmlsec.encryption.impl.EncryptedDataBuilder;
import org.opensaml.xmlsec.signature.support.SignatureConstants;
import org.w3c.dom.Element;
@@ -741,6 +743,19 @@ public class OpenSaml4AuthenticationProviderTests {
.withMessageContaining("did not match any valid issuers");
}
// gh-14931
@Test
public void authenticateWhenAssertionHasProxyRestrictionThenParses() {
OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider();
Response response = response();
Assertion assertion = assertion();
ProxyRestriction condition = new ProxyRestrictionBuilder().buildObject();
assertion.getConditions().getConditions().add(condition);
response.getAssertions().add(assertion);
Saml2AuthenticationToken token = token(signed(response), verifying(registration()));
provider.authenticate(token);
}
private <T extends XMLObject> T build(QName qName) {
return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName);
}
+3 -1
View File
@@ -11,9 +11,11 @@ changelog:
labels: ["type: bug"]
sort: "title"
- title: ":hammer: Dependency Upgrades"
emoji: ":hammer:"
labels: ["type: dependency-upgrade"]
sort: "title"
- title: ":nut_and_bolt: Build Updates"
labels: ["type: task", "in: build"]
sort: "title"
issues:
exclude:
labels: ["status: duplicate"]
+2 -2
View File
@@ -5,8 +5,8 @@ pluginManagement {
}
plugins {
id "com.gradle.enterprise" version "3.12.6"
id "io.spring.ge.conventions" version "0.0.15"
id "com.gradle.develocity" version "3.17.4"
id "io.spring.ge.conventions" version "0.0.17"
}
dependencyResolutionManagement {
@@ -29,6 +29,7 @@ import org.springframework.core.log.LogMessage;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher.MatchResult;
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
@@ -68,7 +69,7 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Authorizing %s", request));
this.logger.trace(LogMessage.format("Authorizing %s", requestLine(request)));
}
for (RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>> mapping : this.mappings) {
@@ -77,7 +78,8 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho
if (matchResult.isMatch()) {
AuthorizationManager<RequestAuthorizationContext> manager = mapping.getEntry();
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Checking authorization on %s using %s", request, manager));
this.logger.trace(
LogMessage.format("Checking authorization on %s using %s", requestLine(request), manager));
}
return manager.check(authentication,
new RequestAuthorizationContext(request, matchResult.getVariables()));
@@ -89,6 +91,10 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho
return DENY;
}
private static String requestLine(HttpServletRequest request) {
return request.getMethod() + " " + UrlUtils.buildRequestUrl(request);
}
/**
* Creates a builder for {@link RequestMatcherDelegatingAuthorizationManager}.
* @return the new {@link Builder} instance
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2024 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.
@@ -130,9 +130,13 @@ public class StrictHttpFirewall implements HttpFirewall {
private static final Predicate<String> ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE = (
s) -> ASSIGNED_AND_NOT_ISO_CONTROL_PATTERN.matcher(s).matches();
private static final Pattern HEADER_VALUE_PATTERN = Pattern.compile("[\\p{IsAssigned}&&[[^\\p{IsControl}]||\\t]]*");
private static final Predicate<String> HEADER_VALUE_PREDICATE = (s) -> HEADER_VALUE_PATTERN.matcher(s).matches();
private Predicate<String> allowedHeaderNames = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
private Predicate<String> allowedHeaderValues = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
private Predicate<String> allowedHeaderValues = HEADER_VALUE_PREDICATE;
private Predicate<String> allowedParameterNames = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2024 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.
@@ -125,7 +125,7 @@ public class AuthenticationWebFilter implements WebFilter {
.flatMap(
(authentication) -> onAuthenticationSuccess(authentication, new WebFilterExchange(exchange, chain)))
.doOnError(AuthenticationException.class,
(ex) -> logger.debug(LogMessage.format("Authentication failed: %s", ex.getMessage())));
(ex) -> logger.debug(LogMessage.format("Authentication failed: %s", ex.getMessage()), ex));
}
protected Mono<Void> onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) {
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2024 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.
@@ -781,6 +781,13 @@ public class StrictHttpFirewallTests {
assertThatExceptionOfType(RequestRejectedException.class).isThrownBy(() -> request.getHeader("Something"));
}
@Test
public void getFirewalledRequestGetHeaderWhenHorizontalTabInHeaderValueThenNoException() {
this.request.addHeader("Something", "tab\tvalue");
HttpServletRequest request = this.firewall.getFirewalledRequest(this.request);
assertThat(request.getHeader("Something")).isEqualTo("tab\tvalue");
}
@Test
public void getFirewalledRequestGetHeaderWhenUndefinedCharacterInHeaderValueThenException() {
this.request.addHeader("Something", "bad\uFFFEvalue");