1
0
mirror of synced 2026-07-15 07:35:11 +00:00

Compare commits

...

89 Commits

Author SHA1 Message Date
github-actions[bot] 17873adf1f Release 5.8.12 2024-04-15 15:21:00 +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
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
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
Josh Cummings 0af0751cfd Treat Map Method Parameter as Immutable
Closes gh-14802
2024-04-04 16:44:14 -06: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
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
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] 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
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] 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 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 37984c2e11 Add GH_TOKEN to set-milestone
Issue gh-14721
2024-03-14 14:45:36 -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 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 e7bff4240a Use GH_ACTIONS_REPO_TOKEN for merge-dependabot-pr.yml
Issue gh-14721
2024-03-14 09:23:31 -03: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
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 8f42c86a57 Use AuthorizationInterceptorsOrder for Post Authorize Method Interceptors
Closes gh-14720
2024-03-12 10:17:45 -03:00
Marcus Hert Da Coregio 5dae6da15a Remove branch filter
Issue gh-14535
2024-03-11 09:25:58 -03:00
Josh Cummings e1c4177cd8 Fix ServerLogoutHandler Order in Docs
Closes gh-14379
2024-03-04 15:42:09 -07:00
Marcus Hert Da Coregio c2e97d7661 Ignore dependabot branches on trigger auto merge 2024-02-29 10:52:44 -03:00
Josh Cummings 94a66f7a26 Change Structure101 Repository URL
Issug gh-14639
2024-02-26 10:03:09 -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
DingHao 45c37c4454 Remove duplicate setSecurityContextHolderStrategy
Closes gh-14592
2024-02-22 12:14:35 -07:00
Josh Cummings 0c70f358d5 Update to Structure101 7.0.24375
Closes gh-14629
2024-02-20 15:43:58 -07: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
Marcus Hert Da Coregio 6230806d56 Change branch pattern
Issue gh-14535
2024-02-16 11:51:53 -03:00
Marcus Hert Da Coregio 2159f3a93d Fix branch pattern
Issue gh-14535
2024-02-16 09:50:42 -03:00
dependabot[bot] dc366cf8da Bump org.springframework:spring-framework-bom from 5.3.31 to 5.3.32
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 5.3.31 to 5.3.32.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.31...v5.3.32)

---
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-02-16 04:04:11 +00:00
Marcus Hert Da Coregio d32202bce3 Revert "Bump org-aspectj from 1.9.20.1 to 1.9.21.1"
This reverts commit a0b1d6317c.
2024-02-15 09:45:49 -03:00
dependabot[bot] 349ac07c10 Bump io.projectreactor:reactor-bom from 2020.0.40 to 2020.0.41
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2020.0.40 to 2020.0.41.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2020.0.40...2020.0.41)

---
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-02-15 06:42:20 -06:00
Marcus Hert Da Coregio 59be5553a1 Fix workflow syntax
Issue gh-14535
2024-02-15 09:23:35 -03:00
Marcus Hert Da Coregio 2bfdb0c6cd Only run workflow for branches that matches [5-9]+.[5-9]+.x
Issue gh-14535
2024-02-14 01:15:16 -03:00
dependabot[bot] 2ed7b857c3 Bump org-eclipse-jetty from 9.4.53.v20231009 to 9.4.54.v20240208
Bumps `org-eclipse-jetty` from 9.4.53.v20231009 to 9.4.54.v20240208.

Updates `org.eclipse.jetty:jetty-server` from 9.4.53.v20231009 to 9.4.54.v20240208

Updates `org.eclipse.jetty:jetty-servlet` from 9.4.53.v20231009 to 9.4.54.v20240208

---
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-02-14 03:57:50 +00:00
dependabot[bot] a0b1d6317c Bump org-aspectj from 1.9.20.1 to 1.9.21.1
Bumps `org-aspectj` from 1.9.20.1 to 1.9.21.1.

Updates `org.aspectj:aspectjrt` from 1.9.20.1 to 1.9.21.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.20.1 to 1.9.21.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-02-14 03:57:41 +00:00
Marcus Hert Da Coregio 731cd6131b Do not try to run trigger dependabot automerge workflow in PRs
Issue gh-14535
2024-02-13 10:45:08 -03:00
dependabot[bot] c2a589734c Bump spring-io/spring-github-workflows
Bumps [spring-io/spring-github-workflows](https://github.com/spring-io/spring-github-workflows) from eaf17a1890b1ef1b337f015d6eb263baaf8c6dab to 1e8b0587a1f4f01697f9753fa3339c3e0d30f396.
- [Release notes](https://github.com/spring-io/spring-github-workflows/releases)
- [Commits](https://github.com/spring-io/spring-github-workflows/compare/eaf17a1890b1ef1b337f015d6eb263baaf8c6dab...1e8b0587a1f4f01697f9753fa3339c3e0d30f396)

---
updated-dependencies:
- dependency-name: spring-io/spring-github-workflows
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 00:57:15 +00:00
dependabot[bot] e5e67f91e9 Bump Gamesight/slack-workflow-status from 1.2.0 to 1.3.0
Bumps [Gamesight/slack-workflow-status](https://github.com/gamesight/slack-workflow-status) from 1.2.0 to 1.3.0.
- [Release notes](https://github.com/gamesight/slack-workflow-status/releases)
- [Commits](https://github.com/gamesight/slack-workflow-status/compare/v1.2.0...v1.3.0)

---
updated-dependencies:
- dependency-name: Gamesight/slack-workflow-status
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 00:57:09 +00:00
Marcus Hert Da Coregio ccb2f06d0d Partially revert fc658d10
OpenIDAuthenticationFilter exists in versions < 6.0

Issue gh-14531
2024-02-07 10:13:34 -03:00
DingHao fc658d10d3 fix security filter sort in javadoc
Closes gh-14531
2024-02-07 09:37:01 -03:00
Marcus Hert Da Coregio e0fc8f37b0 Use latest version of spring-merge-dependabot-pr workflow
Issue gh-14535
2024-02-06 11:05:56 -03:00
Marcus Hert Da Coregio 43ced5291b Only run workflow for spring-projects repositories
Issue gh-14535
2024-02-06 08:18:31 -03:00
Marcus Hert Da Coregio 56c5fc281e Automatically trigger auto merge for Dependabot PRs
Issue gh-14535
2024-02-06 08:06:27 -03:00
Josh Cummings 7c3a6a567e Fix Compilation Errors
Issue gh-14525
2024-02-05 15:18:31 -07:00
Andreas Asplund 07e0b1dc37 Saml2 LogoutFilter Is Placed Before Common LogoutFilter
Closes gh-14525
2024-02-05 15:18:31 -07:00
Marcus Hert Da Coregio 05d3c4b695 Add permission to Edit Dependabot PR workflow
Issue gh-14486
2024-02-02 09:30:50 -03:00
Marcus Hert Da Coregio 5f80cfc705 Automatically assign milestone to Dependabot PR
Issue gh-14486
2024-02-02 09:30:39 -03:00
dependabot[bot] 7011930305 Bump gradle/gradle-build-action from 2 to 3
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 2 to 3.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-29 17:44:51 -07:00
dependabot[bot] 8a75382b2d Bump slackapi/slack-github-action from 1.24.0 to 1.25.0
Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.24.0 to 1.25.0.
- [Release notes](https://github.com/slackapi/slack-github-action/releases)
- [Commits](https://github.com/slackapi/slack-github-action/compare/v1.24.0...v1.25.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-01-29 17:41:43 -07:00
Hans Lindner ca10187fd1 Enhance JWT decoding error handling
Previously, the `decode` method threw a `JwtException` directly when encountering an unsupported algorithm or any exception during parsing. This commit introduces a more robust error handling mechanism. Now, instead of throwing exceptions directly, it returns a `Mono.error()` with a `BadJwtException` containing detailed error information. This approach provides more flexibility and allows the caller to handle errors in a more granular way, by being able to use project reactors onError functionality.

Closes gh-14467
2024-01-25 17:32:10 -07:00
dependabot[bot] 56f486588f Bump io.spring.ge.conventions from 0.0.14 to 0.0.15
Bumps [io.spring.ge.conventions](https://github.com/spring-io/gradle-enterprise-conventions) from 0.0.14 to 0.0.15.
- [Release notes](https://github.com/spring-io/gradle-enterprise-conventions/releases)
- [Commits](https://github.com/spring-io/gradle-enterprise-conventions/compare/v0.0.14...v0.0.15)

---
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-01-17 14:31:01 -03:00
dependabot[bot] 3f5f79d835 Bump io.projectreactor.netty:reactor-netty from 1.0.40 to 1.0.41
Bumps [io.projectreactor.netty:reactor-netty](https://github.com/reactor/reactor-netty) from 1.0.40 to 1.0.41.
- [Release notes](https://github.com/reactor/reactor-netty/releases)
- [Commits](https://github.com/reactor/reactor-netty/compare/v1.0.40...v1.0.41)

---
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-01-12 09:52:45 -06:00
dependabot[bot] 9985580534 Bump io.projectreactor:reactor-bom from 2020.0.39 to 2020.0.40
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2020.0.39 to 2020.0.40.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2020.0.39...2020.0.40)

---
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-01-12 09:42:04 -06:00
dependabot[bot] 24d4abe5fd Bump io-spring-javaformat from 0.0.40 to 0.0.41
Bumps `io-spring-javaformat` from 0.0.40 to 0.0.41.

Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.40 to 0.0.41
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.40...v0.0.41)

Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.40 to 0.0.41
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.40...v0.0.41)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-12 09:37:19 -06:00
Steve Riesenberg 16dc6be3c8 Update copyright year
Issue gh-14329
2023-12-28 12:54:29 -06:00
Geir Hedemark c88aaedb48 Updated broken documentation link in javadocs 2023-12-28 12:54:29 -06:00
daniKir 9203567a20 improve Multitenancy Issuer Validator example Closes gh-14229 2023-12-19 18:04:50 -07:00
Josh Cummings e058b559b8 Polish Method Security Eager-Loading
Issue gh-11596
2023-12-18 15:18:09 -07:00
Josh Cummings 33800c0124 Address eager-loading of infrastructure beans
Closes gh-11596
2023-12-18 14:25:48 -07:00
github-actions[bot] b71962e87d Next development version 2023-12-18 19:49:40 +00:00
github-actions[bot] b97c310aba Release 5.8.9 2023-12-18 19:12:02 +00:00
Josh Cummings 59461d94b0 Clarify RSocket Configuration Docs
Closes gh-13718
2023-12-18 12:02:49 -07:00
Josh Cummings fc007aa373 Check OpenSAML Version in XML Support
Closes gh-12483
2023-12-18 11:51:15 -07:00
Josh Cummings eaaa813ede Fix header value typo
Closes gh-11948
2023-12-18 10:42:50 -07:00
dependabot[bot] 10b3a9b234 Bump Gamesight/slack-workflow-status from 1.0.1 to 1.2.0
Bumps [Gamesight/slack-workflow-status](https://github.com/gamesight/slack-workflow-status) from 1.0.1 to 1.2.0.
- [Release notes](https://github.com/gamesight/slack-workflow-status/releases)
- [Commits](https://github.com/gamesight/slack-workflow-status/compare/v1.0.1...v1.2.0)

---
updated-dependencies:
- dependency-name: Gamesight/slack-workflow-status
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 08:58:50 -03:00
dependabot[bot] e4cc0a4755 Bump slackapi/slack-github-action from 1.19.0 to 1.24.0
Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.19.0 to 1.24.0.
- [Release notes](https://github.com/slackapi/slack-github-action/releases)
- [Commits](https://github.com/slackapi/slack-github-action/compare/v1.19.0...v1.24.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>
2023-12-14 08:58:37 -03:00
dependabot[bot] ff71ef46b7 Bump actions/setup-java from 3 to 4
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 3 to 4.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 08:58:19 -03:00
dependabot[bot] 5593655bbf Bump spring-io/spring-gradle-build-action from 1 to 2
Bumps [spring-io/spring-gradle-build-action](https://github.com/spring-io/spring-gradle-build-action) from 1 to 2.
- [Commits](https://github.com/spring-io/spring-gradle-build-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: spring-io/spring-gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 08:58:09 -03:00
dependabot[bot] 47812e506f Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 08:58:00 -03:00
dependabot[bot] 89fd30f235 Bump io.projectreactor.netty:reactor-netty from 1.0.39 to 1.0.40
Bumps [io.projectreactor.netty:reactor-netty](https://github.com/reactor/reactor-netty) from 1.0.39 to 1.0.40.
- [Release notes](https://github.com/reactor/reactor-netty/releases)
- [Commits](https://github.com/reactor/reactor-netty/compare/v1.0.39...v1.0.40)

---
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>
2023-12-13 09:16:42 -03:00
dependabot[bot] c3c068376a Bump io.projectreactor:reactor-bom from 2020.0.38 to 2020.0.39
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2020.0.38 to 2020.0.39.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2020.0.38...2020.0.39)

---
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>
2023-12-13 09:15:35 -03:00
Marcus Hert Da Coregio 6d68f403fc Document that Shibboleth Repository is Required for SAML Support
Closes gh-14286
2023-12-13 09:11:27 -03:00
Josh Cummings 74d06f020d Update to Latest Boot Property
Closes gh-14252
2023-12-11 11:44:08 -07:00
Candelario e896b14046 Dropped Nimbus Error Message
Closes gh-13730
2023-12-11 10:19:02 -07:00
Josh Cummings be11812fe4 Account for Super-super-interface Inheritance
Closes gh-13625
2023-12-09 11:41:02 -07:00
Steve Riesenberg 9c44b700f5 Add Gradle Enterprise creds to PR builds
Closes gh-14249
2023-12-07 14:28:51 -06:00
dependabot[bot] 40e8b20257 Bump ch.qos.logback:logback-classic from 1.2.12 to 1.2.13
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.2.12 to 1.2.13.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.2.12...v_1.2.13)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-04 08:51:58 -07:00
Josh Cummings c336ca49fb Update Spring MVC Docs
Closes gh-14220
2023-12-01 12:57:46 -07:00
Josh Cummings c623303ca5 Add Logging
Now if the ServletRegistration API available message is shown, it will
also be accompanied with a startup warning in the logs.

Closes gh-14221
2023-12-01 12:57:46 -07:00
Josh Cummings a98baa7522 Polish ServletRegistration API Deferral
Tomcat uses different ServletContext instances from startup- and request-time.
This commit ensures that if the programmatic API isn't available at startup-time,
then use the ServletContext attached to the HttpServletRequest at runtime.

Issue gh-13794
2023-12-01 12:57:45 -07:00
53 changed files with 573 additions and 225 deletions
@@ -31,7 +31,7 @@ jobs:
runjobs: ${{ steps.continue.outputs.runjobs }}
project_version: ${{ steps.continue.outputs.project_version }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- id: continue
name: Determine if should continue
run: |
@@ -49,15 +49,15 @@ jobs:
runs-on: ${{ matrix.os }}
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'adopt'
cache: 'gradle'
- name: Set up Gradle
uses: gradle/gradle-build-action@v2
uses: gradle/gradle-build-action@v3
- name: Set up gradle user name
run: echo 'systemProp.user.name=spring-builds+github' >> gradle.properties
- name: Build with Gradle
@@ -72,9 +72,9 @@ jobs:
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
@@ -90,9 +90,9 @@ jobs:
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
@@ -114,9 +114,9 @@ jobs:
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
@@ -131,9 +131,9 @@ jobs:
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
@@ -155,9 +155,9 @@ jobs:
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
@@ -176,9 +176,9 @@ jobs:
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
@@ -206,11 +206,11 @@ jobs:
TOKEN: ${{ github.token }}
VERSION: ${{ needs.prerequisites.outputs.project_version }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
@@ -243,7 +243,7 @@ jobs:
./gradlew createGitHubRelease -PnextVersion=$VERSION -Pbranch=$BRANCH -PcreateRelease=true -PgitHubAccessToken=$TOKEN
- name: Announce Release on Slack
id: spring-security-announcing
uses: slackapi/slack-github-action@v1.19.0
uses: slackapi/slack-github-action@v1.25.0
with:
payload: |
{
@@ -287,9 +287,9 @@ jobs:
TOKEN: ${{ github.token }}
VERSION: ${{ needs.prerequisites.outputs.project_version }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
if: github.repository_owner == 'spring-projects'
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: docs-build
fetch-depth: 1
+52
View File
@@ -0,0 +1,52 @@
name: Merge Dependabot PR
on: pull_request_target
run-name: Merge Dependabot PR ${{ github.ref_name }}
permissions: write-all
jobs:
merge-dependabot-pr:
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'
steps:
- uses: actions/checkout@v4
with:
show-progress: false
ref: ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set Milestone to Dependabot Pull Request
id: set-milestone
run: |
if test -f pom.xml
then
CURRENT_VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout)
else
CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }')
fi
export CANDIDATE_VERSION=${CURRENT_VERSION/-SNAPSHOT}
MILESTONE=$(gh api repos/$GITHUB_REPOSITORY/milestones --jq 'map(select(.due_on != null and (.title | startswith(env.CANDIDATE_VERSION)))) | .[0] | .title')
if [ -z $MILESTONE ]
then
gh run cancel ${{ github.run_id }}
echo "::warning title=Cannot merge::No scheduled milestone for $CURRENT_VERSION version"
else
gh pr edit ${{ github.event.pull_request.number }} --milestone $MILESTONE
echo mergeEnabled=true >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Merge Dependabot pull request
if: steps.set-milestone.outputs.mergeEnabled
run: gh pr merge ${{ github.event.pull_request.number }} --auto --rebase
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
@@ -32,7 +32,7 @@ jobs:
actions: read
steps:
- name: Send Slack message
uses: Gamesight/slack-workflow-status@v1.0.1
uses: Gamesight/slack-workflow-status@v1.3.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
+7 -2
View File
@@ -2,6 +2,11 @@ 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
@@ -11,9 +16,9 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
@@ -0,0 +1,22 @@
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
@@ -23,11 +23,11 @@ jobs:
steps:
- id: checkout-source
name: Checkout Source Code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '11'
distribution: 'adopt'
@@ -72,7 +72,7 @@ jobs:
- id: send-slack-notification
name: Send Slack message
if: failure()
uses: Gamesight/slack-workflow-status@v1.0.1
uses: Gamesight/slack-workflow-status@v1.3.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
+1
View File
@@ -148,5 +148,6 @@ tasks.register('cloneSamples', 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);
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2023 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.
@@ -149,7 +149,7 @@ public class AuthenticationManagerBuilder
* {@link #getDefaultUserDetailsService()} method. Note that additional
* {@link UserDetailsService}'s may override this {@link UserDetailsService} as the
* default. See the <a href=
* "https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#user-schema"
* "https://docs.spring.io/spring-security/reference/servlet/appendix/database-schema.html"
* >User Schema</a> section of the reference for the default schema.
* </p>
* @return a {@link JdbcUserDetailsManagerConfigurer} to allow customization of the
@@ -43,6 +43,7 @@ import org.springframework.security.config.core.GrantedAuthorityDefaults;
* @since 5.0
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
class ReactiveMethodSecurityConfiguration implements ImportAware {
private int advisorOrder;
@@ -51,16 +52,17 @@ class ReactiveMethodSecurityConfiguration implements ImportAware {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
MethodSecurityMetadataSourceAdvisor methodSecurityInterceptor(AbstractMethodSecurityMetadataSource source) {
static MethodSecurityMetadataSourceAdvisor methodSecurityInterceptor(AbstractMethodSecurityMetadataSource source,
ReactiveMethodSecurityConfiguration configuration) {
MethodSecurityMetadataSourceAdvisor advisor = new MethodSecurityMetadataSourceAdvisor(
"securityMethodInterceptor", source, "methodMetadataSource");
advisor.setOrder(this.advisorOrder);
advisor.setOrder(configuration.advisorOrder);
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
DelegatingMethodSecurityMetadataSource methodMetadataSource(
static DelegatingMethodSecurityMetadataSource methodMetadataSource(
MethodSecurityExpressionHandler methodSecurityExpressionHandler) {
ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(
methodSecurityExpressionHandler);
@@ -70,7 +72,7 @@ class ReactiveMethodSecurityConfiguration implements ImportAware {
}
@Bean
PrePostAdviceReactiveMethodInterceptor securityMethodInterceptor(AbstractMethodSecurityMetadataSource source,
static PrePostAdviceReactiveMethodInterceptor securityMethodInterceptor(AbstractMethodSecurityMetadataSource source,
MethodSecurityExpressionHandler handler) {
ExpressionBasedPostInvocationAdvice postAdvice = new ExpressionBasedPostInvocationAdvice(handler);
ExpressionBasedPreInvocationAdvice preAdvice = new ExpressionBasedPreInvocationAdvice();
@@ -80,10 +82,11 @@ class ReactiveMethodSecurityConfiguration implements ImportAware {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler() {
static DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler(
ReactiveMethodSecurityConfiguration configuration) {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
if (this.grantedAuthorityDefaults != null) {
handler.setDefaultRolePrefix(this.grantedAuthorityDefaults.getRolePrefix());
if (configuration.grantedAuthorityDefaults != null) {
handler.setDefaultRolePrefix(configuration.grantedAuthorityDefaults.getRolePrefix());
}
return handler;
}
@@ -23,13 +23,16 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.function.Function;
import javax.servlet.DispatcherType;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpMethod;
@@ -44,7 +47,6 @@ import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
@@ -76,6 +78,8 @@ public abstract class AbstractRequestMatcherRegistry<C> {
AbstractRequestMatcherRegistry.class.getClassLoader());
}
private final Log logger = LogFactory.getLog(getClass());
protected final void setApplicationContext(ApplicationContext context) {
this.context = context;
}
@@ -327,7 +331,12 @@ public abstract class AbstractRequestMatcherRegistry<C> {
matchers.add(resolve(ant, mvc, servletContext));
}
else {
matchers.add(new DeferredRequestMatcher(() -> resolve(ant, mvc, servletContext), mvc, ant));
this.logger
.warn("The ServletRegistration API was not available at startup time. This may be due to a misconfiguration; "
+ "if you are using AbstractSecurityWebApplicationInitializer, please double-check the recommendations outlined in "
+ "https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#abstractsecuritywebapplicationinitializer-with-spring-mvc");
matchers.add(new DeferredRequestMatcher((request) -> resolve(ant, mvc, request.getServletContext()),
mvc, ant));
}
}
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
@@ -584,27 +593,34 @@ public abstract class AbstractRequestMatcherRegistry<C> {
static class DeferredRequestMatcher implements RequestMatcher {
final Supplier<RequestMatcher> requestMatcher;
final Function<HttpServletRequest, RequestMatcher> requestMatcherFactory;
final AtomicReference<String> description = new AtomicReference<>();
DeferredRequestMatcher(Supplier<RequestMatcher> resolver, RequestMatcher... candidates) {
this.requestMatcher = SingletonSupplier.of(() -> {
RequestMatcher matcher = resolver.get();
this.description.set(matcher.toString());
return matcher;
});
volatile RequestMatcher requestMatcher;
DeferredRequestMatcher(Function<HttpServletRequest, RequestMatcher> resolver, RequestMatcher... candidates) {
this.requestMatcherFactory = (request) -> {
if (this.requestMatcher == null) {
synchronized (this) {
if (this.requestMatcher == null) {
this.requestMatcher = resolver.apply(request);
}
}
}
return this.requestMatcher;
};
this.description.set("Deferred " + Arrays.toString(candidates));
}
@Override
public boolean matches(HttpServletRequest request) {
return this.requestMatcher.get().matches(request);
return this.requestMatcherFactory.apply(request).matches(request);
}
@Override
public MatchResult matcher(HttpServletRequest request) {
return this.requestMatcher.get().matcher(request);
return this.requestMatcherFactory.apply(request).matcher(request);
}
@Override
@@ -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.
@@ -28,6 +28,7 @@ import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@@ -38,7 +39,11 @@ import org.springframework.security.web.authentication.rememberme.RememberMeAuth
import org.springframework.security.web.authentication.switchuser.SwitchUserFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
import org.springframework.security.web.context.SecurityContextHolderFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
@@ -46,6 +51,7 @@ import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.web.filter.CorsFilter;
/**
* @param <H>
@@ -127,15 +133,24 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
* The ordering of the Filters is:
*
* <ul>
* <li>{@link ForceEagerSessionCreationFilter}</li>
* <li>{@link DisableEncodeUrlFilter}</li>
* <li>{@link ForceEagerSessionCreationFilter}</li>
* <li>{@link ChannelProcessingFilter}</li>
* <li>{@link WebAsyncManagerIntegrationFilter}</li>
* <li>{@link SecurityContextHolderFilter}</li>
* <li>{@link SecurityContextPersistenceFilter}</li>
* <li>{@link HeaderWriterFilter}</li>
* <li>{@link CorsFilter}</li>
* <li>{@link CsrfFilter}</li>
* <li>{@link LogoutFilter}</li>
* <li>{@link org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter}</li>
* <li>{@link org.springframework.security.saml2.provider.service.web.Saml2WebSsoAuthenticationRequestFilter}</li>
* <li>{@link X509AuthenticationFilter}</li>
* <li>{@link AbstractPreAuthenticatedProcessingFilter}</li>
* <li><a href="
* {@docRoot}/org/springframework/security/cas/web/CasAuthenticationFilter.html">CasAuthenticationFilter</a></li>
* <li>{@link org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter}</li>
* <li>{@link org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter}</li>
* <li>{@link UsernamePasswordAuthenticationFilter}</li>
* <li>{@link OpenIDAuthenticationFilter}</li>
* <li>{@link org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter}</li>
@@ -149,9 +164,11 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
* <li>{@link JaasApiIntegrationFilter}</li>
* <li>{@link RememberMeAuthenticationFilter}</li>
* <li>{@link AnonymousAuthenticationFilter}</li>
* <li>{@link org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter}</li>
* <li>{@link SessionManagementFilter}</li>
* <li>{@link ExceptionTranslationFilter}</li>
* <li>{@link FilterSecurityInterceptor}</li>
* <li>{@link AuthorizationFilter}</li>
* <li>{@link SwitchUserFilter}</li>
* </ul>
* @param filter the {@link Filter} to add
@@ -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.
@@ -801,7 +801,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
* replaced with "#". For example:
*
* <pre>
* X-XSS-Protection: 1 ; mode=block
* X-XSS-Protection: 1; mode=block
* </pre>
* @param headerValue the new header value
* @since 5.8
@@ -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;
}
@@ -268,12 +268,14 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
return postProcess(logoutResponseFilter);
}
private LogoutFilter createRelyingPartyLogoutFilter(RelyingPartyRegistrationResolver registrations) {
private Saml2RelyingPartyInitiatedLogoutFilter createRelyingPartyLogoutFilter(
RelyingPartyRegistrationResolver registrations) {
LogoutHandler[] logoutHandlers = this.logoutHandlers.toArray(new LogoutHandler[0]);
Saml2RelyingPartyInitiatedLogoutSuccessHandler logoutRequestSuccessHandler = createSaml2LogoutRequestSuccessHandler(
registrations);
logoutRequestSuccessHandler.setLogoutRequestRepository(this.logoutRequestConfigurer.logoutRequestRepository);
LogoutFilter logoutFilter = new LogoutFilter(logoutRequestSuccessHandler, logoutHandlers);
Saml2RelyingPartyInitiatedLogoutFilter logoutFilter = new Saml2RelyingPartyInitiatedLogoutFilter(
logoutRequestSuccessHandler, logoutHandlers);
logoutFilter.setLogoutRequestMatcher(createLogoutMatcher());
return postProcess(logoutFilter);
}
@@ -568,4 +570,12 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
}
private static class Saml2RelyingPartyInitiatedLogoutFilter extends LogoutFilter {
Saml2RelyingPartyInitiatedLogoutFilter(LogoutSuccessHandler logoutSuccessHandler, LogoutHandler... handlers) {
super(logoutSuccessHandler, handlers);
}
}
}
@@ -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 {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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,6 +16,7 @@
package org.springframework.security.config.http;
import org.opensaml.core.Version;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
@@ -27,6 +28,7 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@@ -35,6 +37,8 @@ import org.springframework.util.StringUtils;
*/
final class Saml2LoginBeanDefinitionParserUtils {
private static final String OPEN_SAML_4_VERSION = "4";
private static final String ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF = "relying-party-registration-repository-ref";
private static final String ATT_AUTHENTICATION_REQUEST_REPOSITORY_REF = "authentication-request-repository-ref";
@@ -78,15 +82,27 @@ final class Saml2LoginBeanDefinitionParserUtils {
.rootBeanDefinition(DefaultRelyingPartyRegistrationResolver.class)
.addConstructorArgValue(relyingPartyRegistrationRepository)
.getBeanDefinition();
if (version().startsWith("4")) {
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver")
.addConstructorArgValue(defaultRelyingPartyRegistrationResolver)
.getBeanDefinition();
}
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver")
"org.springframework.security.saml2.provider.service.web.authentication.OpenSamlAuthenticationRequestResolver")
.addConstructorArgValue(defaultRelyingPartyRegistrationResolver)
.getBeanDefinition();
}
static BeanDefinition createAuthenticationProvider() {
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider")
if (version().startsWith("4")) {
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider")
.getBeanDefinition();
}
return BeanDefinitionBuilder
.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider")
.getBeanDefinition();
}
@@ -108,4 +124,17 @@ final class Saml2LoginBeanDefinitionParserUtils {
.getBeanDefinition();
}
static String version() {
String version = Version.getVersion();
if (StringUtils.hasText(version)) {
return version;
}
boolean openSaml4ClassPresent = ClassUtils
.isPresent("org.opensaml.core.xml.persist.impl.PassthroughSourceStrategy", null);
if (openSaml4ClassPresent) {
return OPEN_SAML_4_VERSION;
}
throw new IllegalStateException("cannot determine OpenSAML version");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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,6 +16,7 @@
package org.springframework.security.config.http;
import org.opensaml.core.Version;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
@@ -25,6 +26,7 @@ import org.springframework.security.saml2.provider.service.authentication.logout
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlLogoutResponseValidator;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@@ -33,6 +35,8 @@ import org.springframework.util.StringUtils;
*/
final class Saml2LogoutBeanDefinitionParserUtils {
private static final String OPEN_SAML_4_VERSION = "4";
private static final String ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF = "relying-party-registration-repository-ref";
private static final String ATT_LOGOUT_REQUEST_VALIDATOR_REF = "logout-request-validator-ref";
@@ -62,8 +66,14 @@ final class Saml2LogoutBeanDefinitionParserUtils {
if (StringUtils.hasText(logoutResponseResolver)) {
return new RuntimeBeanReference(logoutResponseResolver);
}
if (version().startsWith("4")) {
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver")
.addConstructorArgValue(registrations)
.getBeanDefinition();
}
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver")
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSamlLogoutResponseResolver")
.addConstructorArgValue(registrations)
.getBeanDefinition();
}
@@ -97,10 +107,29 @@ final class Saml2LogoutBeanDefinitionParserUtils {
if (StringUtils.hasText(logoutRequestResolver)) {
return new RuntimeBeanReference(logoutRequestResolver);
}
if (version().startsWith("4")) {
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutRequestResolver")
.addConstructorArgValue(registrations)
.getBeanDefinition();
}
return BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutRequestResolver")
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSamlLogoutRequestResolver")
.addConstructorArgValue(registrations)
.getBeanDefinition();
}
static String version() {
String version = Version.getVersion();
if (StringUtils.hasText(version)) {
return version;
}
boolean openSaml4ClassPresent = ClassUtils
.isPresent("org.opensaml.core.xml.persist.impl.PassthroughSourceStrategy", null);
if (openSaml4ClassPresent) {
return OPEN_SAML_4_VERSION;
}
throw new IllegalStateException("cannot determine OpenSAML version");
}
}
@@ -385,7 +385,7 @@ public class AbstractRequestMatcherRegistryTests {
List<RequestMatcher> requestMatchers = new ArrayList<>();
for (RequestMatcher requestMatcher : wrappedMatchers) {
if (requestMatcher instanceof AbstractRequestMatcherRegistry.DeferredRequestMatcher) {
requestMatchers.add(((DeferredRequestMatcher) requestMatcher).requestMatcher.get());
requestMatchers.add(((DeferredRequestMatcher) requestMatcher).requestMatcher);
}
else {
requestMatchers.add(requestMatcher);
@@ -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);
}
@@ -75,7 +75,7 @@ public class HeaderSpecTests {
this.expectedHeaders.add(HttpHeaders.EXPIRES, "0");
this.expectedHeaders.add(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS, "nosniff");
this.expectedHeaders.add(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, "DENY");
this.expectedHeaders.add(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block");
this.expectedHeaders.add(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block");
}
@Test
@@ -320,7 +320,7 @@ public class HeaderSpecTests {
@Test
public void headersWhenXssProtectionValueEnabledModeBlockThenXssProtectionWritten() {
this.expectedHeaders.set(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block");
this.expectedHeaders.set(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block");
// @formatter:off
this.http.headers()
.xssProtection()
@@ -70,7 +70,7 @@ class ServerHeadersDslTests {
.expectHeader().valueEquals(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")
.expectHeader().valueEquals(HttpHeaders.EXPIRES, "0")
.expectHeader().valueEquals(HttpHeaders.PRAGMA, "no-cache")
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block")
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block")
}
@EnableWebFluxSecurity
@@ -123,7 +123,7 @@ class ServerHttpSecurityDslTests {
.expectHeader().valueEquals(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")
.expectHeader().valueEquals(HttpHeaders.EXPIRES, "0")
.expectHeader().valueEquals(HttpHeaders.PRAGMA, "no-cache")
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block")
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block")
}
@EnableWebFluxSecurity
@@ -56,7 +56,7 @@ class ServerXssProtectionDslTests {
this.client.get()
.uri("/")
.exchange()
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block")
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block")
}
@EnableWebFluxSecurity
@@ -61,7 +61,7 @@ public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
private boolean isFullyAuthenticated(Authentication authentication) {
return (!this.authenticationTrustResolver.isAnonymous(authentication)
return authentication != null && (!this.authenticationTrustResolver.isAnonymous(authentication)
&& !this.authenticationTrustResolver.isRememberMe(authentication));
}
@@ -95,17 +95,28 @@ final class AuthorizationAnnotationUtils {
private static <A extends Annotation> boolean hasDuplicate(MergedAnnotations mergedAnnotations,
Class<A> annotationType) {
boolean alreadyFound = false;
MergedAnnotation<Annotation> alreadyFound = null;
for (MergedAnnotation<Annotation> mergedAnnotation : mergedAnnotations) {
if (isSynthetic(mergedAnnotation.getSource())) {
continue;
}
if (mergedAnnotation.getType() == annotationType) {
if (alreadyFound) {
return true;
}
alreadyFound = true;
if (mergedAnnotation.getType() != annotationType) {
continue;
}
if (alreadyFound == null) {
alreadyFound = mergedAnnotation;
continue;
}
// https://github.com/spring-projects/spring-framework/issues/31803
if (!mergedAnnotation.getSource().equals(alreadyFound.getSource())) {
return true;
}
if (mergedAnnotation.getRoot().getType() != alreadyFound.getRoot().getType()) {
return true;
}
}
return false;
@@ -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;
}
@@ -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
@@ -41,6 +41,13 @@ class AuthorizationAnnotationUtilsTests {
.isThrownBy(() -> AuthorizationAnnotationUtils.findUniqueAnnotation(method, PreAuthorize.class));
}
@Test // gh-13625
void annotationsFromSuperSuperInterfaceShouldNotTriggerAnnotationConfigurationException() throws Exception {
Method method = HelloImpl.class.getMethod("sayHello");
assertThatNoException()
.isThrownBy(() -> AuthorizationAnnotationUtils.findUniqueAnnotation(method, PreAuthorize.class));
}
private interface BaseRepository<T> {
Iterable<T> findAll();
@@ -55,4 +62,24 @@ class AuthorizationAnnotationUtilsTests {
}
private interface Hello {
@PreAuthorize("hasRole('someRole')")
String sayHello();
}
private interface SayHello extends Hello {
}
private static class HelloImpl implements SayHello {
@Override
public String sayHello() {
return "hello";
}
}
}
@@ -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 {
@@ -62,7 +62,10 @@ This configuration enables <<rsocket-authentication-simple,simple authentication
For Spring Security to work we need to apply `SecuritySocketAcceptorInterceptor` to the `ServerRSocketFactory`.
This is what connects our `PayloadSocketAcceptorInterceptor` we created with the RSocket infrastructure.
In a Spring Boot application this is done automatically using `RSocketSecurityAutoConfiguration` with the following code.
Spring Boot registers it automatically in `RSocketSecurityAutoConfiguration` when you include {gh-samples-url}/reactive/rsocket/hello-security/build.gradle[the correct dependencies].
Or, if you are not using Boot's auto-configuration, you can register it manually in the following way:
[tabs]
======
@@ -91,6 +94,8 @@ fun springSecurityRSocketSecurity(interceptor: SecuritySocketAcceptorInterceptor
----
======
To customize the interceptor itself, use `RSocketSecurity` to add <<rsocket-authentication,authentication>> and <<rsocket-authorization,authorization>>.
[[rsocket-authentication]]
== RSocket Authentication
@@ -370,7 +370,7 @@ spring:
oauth2:
resourceserver:
jwt:
jws-algorithm: RS512
jws-algorithms: RS512
jwk-set-uri: https://idp.example.org/.well-known/jwks.json
----
@@ -112,7 +112,7 @@ public class SecurityWebApplicationInitializer
This would simply only register the springSecurityFilterChain Filter for every URL in your application.
After that we would ensure that `WebSecurityConfig` was loaded in our existing ApplicationInitializer.
For example, if we were using Spring MVC it would be added in the `getRootConfigClasses()`
For example, if we were using Spring MVC it would be added in the `getServletConfigClasses()`
[[message-web-application-inititializer-java]]
[source,java]
@@ -121,14 +121,42 @@ public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { WebSecurityConfig.class };
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
}
// ... other overrides ...
}
----
The reason for this is that Spring Security needs to be able to inspect some Spring MVC configuration in order to appropriately configure xref:servlet/authorization/authorize-http-requests.adoc#_request_matchers[underlying request matchers], so they need to be in the same application context.
Placing Spring Security in `getRootConfigClasses` places it into a parent application context that may not be able to find Spring MVC's `HandlerMappingIntrospector`.
==== Configuring for Multiple Spring MVC Dispatchers
If desired, any Spring Security configuration that is unrelated to Spring MVC may be placed in a different configuration class like so:
[source,java]
----
public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { NonWebSecurityConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
}
// ... other overrides ...
}
----
This can be helpful if you have multiple instances of `AbstractAnnotationConfigDispatcherServletInitializer` and don't want to duplicate the general security configuration across both of them.
[[jc-httpsecurity]]
== HttpSecurity
@@ -513,7 +513,7 @@ spring:
oauth2:
resourceserver:
jwt:
jws-algorithm: RS512
jws-algorithms: RS512
jwk-set-uri: https://idp.example.org/.well-known/jwks.json
----
@@ -374,29 +374,22 @@ Java::
----
@Component
public class TenantJwtIssuerValidator implements OAuth2TokenValidator<Jwt> {
private final TenantRepository tenants;
private final Map<String, JwtIssuerValidator> validators = new ConcurrentHashMap<>();
private final TenantRepository tenants;
public TenantJwtIssuerValidator(TenantRepository tenants) {
this.tenants = tenants;
}
private final OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN, "The iss claim is not valid",
"https://tools.ietf.org/html/rfc6750#section-3.1");
@Override
public OAuth2TokenValidatorResult validate(Jwt token) {
return this.validators.computeIfAbsent(toTenant(token), this::fromTenant)
.validate(token);
}
public TenantJwtIssuerValidator(TenantRepository tenants) {
this.tenants = tenants;
}
private String toTenant(Jwt jwt) {
return jwt.getIssuer();
}
private JwtIssuerValidator fromTenant(String tenant) {
return Optional.ofNullable(this.tenants.findById(tenant))
.map(t -> t.getAttribute("issuer"))
.map(JwtIssuerValidator::new)
.orElseThrow(() -> new IllegalArgumentException("unknown tenant"));
}
@Override
public OAuth2TokenValidatorResult validate(Jwt token) {
if(this.tenants.findById(token.getIssuer()) != null) {
return OAuth2TokenValidatorResult.success();
}
return OAuth2TokenValidatorResult.failure(this.error);
}
}
----
@@ -405,32 +398,17 @@ Kotlin::
[source,kotlin,role="secondary"]
----
@Component
class TenantJwtIssuerValidator(tenants: TenantRepository) : OAuth2TokenValidator<Jwt> {
private val tenants: TenantRepository
private val validators: MutableMap<String, JwtIssuerValidator> = ConcurrentHashMap()
class TenantJwtIssuerValidator(private val tenants: TenantRepository) : OAuth2TokenValidator<Jwt> {
private val error: OAuth2Error = OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN, "The iss claim is not valid",
"https://tools.ietf.org/html/rfc6750#section-3.1")
override fun validate(token: Jwt): OAuth2TokenValidatorResult {
return validators.computeIfAbsent(toTenant(token)) { tenant: String -> fromTenant(tenant) }
.validate(token)
}
private fun toTenant(jwt: Jwt): String {
return jwt.issuer.toString()
}
private fun fromTenant(tenant: String): JwtIssuerValidator {
return Optional.ofNullable(tenants.findById(tenant))
.map({ t -> t.getAttribute("issuer") })
.map({ JwtIssuerValidator() })
.orElseThrow({ IllegalArgumentException("unknown tenant") })
}
init {
this.tenants = tenants
return if (tenants.findById(token.issuer) != null)
OAuth2TokenValidatorResult.success() else OAuth2TokenValidatorResult.failure(error)
}
}
----
======
Now that we have a tenant-aware processor and a tenant-aware validator, we can proceed with creating our xref:servlet/oauth2/resource-server/jwt.adoc#oauth2resourceserver-jwt-architecture-jwtdecoder[`JwtDecoder`]:
[tabs]
@@ -55,7 +55,42 @@ image:{icondir}/number_4.png[] If authentication is successful, then __Success__
== Minimal Dependencies
SAML 2.0 service provider support resides in `spring-security-saml2-service-provider`.
It builds off of the OpenSAML library.
It builds off of the OpenSAML library, and, for that reason, you must also include the Shibboleth Maven repository in your build configuration.
Check https://shibboleth.atlassian.net/wiki/spaces/DEV/pages/1123844333/Use+of+Maven+Central#Publishing-to-Maven-Central[this link] for more details about why a separate repository is needed.
[tabs]
======
Maven::
+
[source,xml,role="primary"]
----
<repositories>
<!-- ... -->
<repository>
<id>shibboleth-releases</id>
<url>https://build.shibboleth.net/nexus/content/repositories/releases/</url>
</repository>
</repositories>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-saml2-service-provider</artifactId>
</dependency>
----
Gradle::
+
[source,groovy,role="secondary"]
----
repositories {
// ...
maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
}
dependencies {
// ...
implementation 'org.springframework.security:spring-security-saml2-service-provider'
}
----
======
[[servlet-saml2login-minimalconfiguration]]
== Minimal Configuration
+1 -1
View File
@@ -1,5 +1,5 @@
springBootVersion=2.7.12
version=5.8.9-SNAPSHOT
version=5.8.12
samplesBranch=5.8.x
org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.parallel=true
+6 -6
View File
@@ -2,12 +2,12 @@
com-squareup-okhttp3 = "3.14.9"
io-r2dbc = "0.9.1.RELEASE"
io-rsocket = "1.1.4"
io-spring-javaformat = "0.0.40"
io-spring-javaformat = "0.0.41"
io-spring-nohttp = "0.0.11"
org-apache-directory-server = "1.5.5"
org-aspectj = "1.9.20.1"
org-bouncycastle = "1.70"
org-eclipse-jetty = "9.4.53.v20231009"
org-eclipse-jetty = "9.4.54.v20240208"
org-jetbrains-kotlin = "1.7.22"
org-jetbrains-kotlinx = "1.6.4"
org-junit-jupiter = "5.9.3"
@@ -15,10 +15,10 @@ org-mockito = "4.8.1"
org-opensaml4 = "4.1.0"
org-opensaml3 = "3.4.6"
org-slf4j = "1.7.36"
org-springframework = "5.3.31"
org-springframework = "5.3.34"
[libraries]
ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.2.12"
ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.2.13"
com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.13.5"
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"
@@ -30,8 +30,8 @@ com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:4.0.14"
commons-collections = "commons-collections:commons-collections:3.2.2"
io-freefair-gradle-aspectj-plugin = "io.freefair.gradle:aspectj-plugin:6.5.1"
io-mockk = "io.mockk:mockk:1.13.3"
io-projectreactor-netty-reactor-netty = "io.projectreactor.netty:reactor-netty:1.0.39"
io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2020.0.38"
io-projectreactor-netty-reactor-netty = "io.projectreactor.netty:reactor-netty:1.0.44"
io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2020.0.43"
io-projectreactor-tools-blockhound = "io.projectreactor.tools:blockhound:1.0.8.RELEASE"
io-r2dbc-r2dbc-h2 = { module = "io.r2dbc:r2dbc-h2", version.ref = "io-r2dbc" }
io-r2dbc-r2dbc-spi-test = { module = "io.r2dbc:r2dbc-spi-test", version.ref = "io-r2dbc" }
@@ -144,6 +144,9 @@ public final class NimbusJwtDecoder implements JwtDecoder {
}
catch (Exception ex) {
this.logger.trace("Failed to parse token", ex);
if (ex instanceof ParseException) {
throw new BadJwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, "Malformed token"), ex);
}
throw new BadJwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), 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.
@@ -145,20 +145,17 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
}
@Override
public Mono<Jwt> decode(String token) throws JwtException {
JWT jwt = parse(token);
if (jwt instanceof PlainJWT) {
throw new BadJwtException("Unsupported algorithm of " + jwt.getHeader().getAlgorithm());
}
return this.decode(jwt);
}
private JWT parse(String token) {
public Mono<Jwt> decode(String token) {
try {
return JWTParser.parse(token);
JWT jwt = JWTParser.parse(token);
if (jwt instanceof PlainJWT) {
return Mono.error(new BadJwtException("Unsupported algorithm of " + jwt.getHeader().getAlgorithm()));
}
return this.decode(jwt);
}
catch (Exception ex) {
throw new BadJwtException("An error occurred while attempting to decode the Jwt: " + ex.getMessage(), ex);
return Mono.error(new BadJwtException(
"An error occurred while attempting to decode the Jwt: " + ex.getMessage(), ex));
}
}
@@ -97,6 +97,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
*/
public class NimbusJwtDecoderTests {
private static final String MALFORMED_TOKEN = "eyJhbGciOiJSUzI1NiJ9.eyJuYmYiOnt9LCJleHAiOjQ2ODQyMjUwODd9";
private static final String JWK_SET = "{\"keys\":[{\"p\":\"49neceJFs8R6n7WamRGy45F5Tv0YM-R2ODK3eSBUSLOSH2tAqjEVKOkLE5fiNA3ygqq15NcKRadB2pTVf-Yb5ZIBuKzko8bzYIkIqYhSh_FAdEEr0vHF5fq_yWSvc6swsOJGqvBEtuqtJY027u-G2gAQasCQdhyejer68zsTn8M\",\"kty\":\"RSA\",\"q\":\"tWR-ysspjZ73B6p2vVRVyHwP3KQWL5KEQcdgcmMOE_P_cPs98vZJfLhxobXVmvzuEWBpRSiqiuyKlQnpstKt94Cy77iO8m8ISfF3C9VyLWXi9HUGAJb99irWABFl3sNDff5K2ODQ8CmuXLYM25OwN3ikbrhEJozlXg_NJFSGD4E\",\"d\":\"FkZHYZlw5KSoqQ1i2RA2kCUygSUOf1OqMt3uomtXuUmqKBm_bY7PCOhmwbvbn4xZYEeHuTR8Xix-0KpHe3NKyWrtRjkq1T_un49_1LLVUhJ0dL-9_x0xRquVjhl_XrsRXaGMEHs8G9pLTvXQ1uST585gxIfmCe0sxPZLvwoic-bXf64UZ9BGRV3lFexWJQqCZp2S21HfoU7wiz6kfLRNi-K4xiVNB1gswm_8o5lRuY7zB9bRARQ3TS2G4eW7p5sxT3CgsGiQD3_wPugU8iDplqAjgJ5ofNJXZezoj0t6JMB_qOpbrmAM1EnomIPebSLW7Ky9SugEd6KMdL5lW6AuAQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"qi\":\"wdkFu_tV2V1l_PWUUimG516Zvhqk2SWDw1F7uNDD-Lvrv_WNRIJVzuffZ8WYiPy8VvYQPJUrT2EXL8P0ocqwlaSTuXctrORcbjwgxDQDLsiZE0C23HYzgi0cofbScsJdhcBg7d07LAf7cdJWG0YVl1FkMCsxUlZ2wTwHfKWf-v4\",\"dp\":\"uwnPxqC-IxG4r33-SIT02kZC1IqC4aY7PWq0nePiDEQMQWpjjNH50rlq9EyLzbtdRdIouo-jyQXB01K15-XXJJ60dwrGLYNVqfsTd0eGqD1scYJGHUWG9IDgCsxyEnuG3s0AwbW2UolWVSsU2xMZGb9PurIUZECeD1XDZwMp2s0\",\"dq\":\"hra786AunB8TF35h8PpROzPoE9VJJMuLrc6Esm8eZXMwopf0yhxfN2FEAvUoTpLJu93-UH6DKenCgi16gnQ0_zt1qNNIVoRfg4rw_rjmsxCYHTVL3-RDeC8X_7TsEySxW0EgFTHh-nr6I6CQrAJjPM88T35KHtdFATZ7BCBB8AE\",\"n\":\"oXJ8OyOv_eRnce4akdanR4KYRfnC2zLV4uYNQpcFn6oHL0dj7D6kxQmsXoYgJV8ZVDn71KGmuLvolxsDncc2UrhyMBY6DVQVgMSVYaPCTgW76iYEKGgzTEw5IBRQL9w3SRJWd3VJTZZQjkXef48Ocz06PGF3lhbz4t5UEZtdF4rIe7u-977QwHuh7yRPBQ3sII-cVoOUMgaXB9SHcGF2iZCtPzL_IffDUcfhLQteGebhW8A6eUHgpD5A1PQ-JCw_G7UOzZAjjDjtNM2eqm8j-Ms_gqnm4MiCZ4E-9pDN77CAAPVN7kuX6ejs9KBXpk01z48i9fORYk9u7rAkh1HuQw\"}]}";
private static final String NEW_KID_JWK_SET = "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"AQAB\",\"kid\":\"two\",\"n\":\"ra9UJw4I0fCHuOqr1xWJsh-qcVeZWtKEU3uoqq1sAg5fG67dujNCm_Q16yuO0ZdDiU0vlJkbc_MXFAvm4ZxdJ_qR7PAneV-BOGNtLpSaiPclscCy3m7zjRWkaqwt9ZZEsdK5UqXyPlBpcYhNKsmnQGjnX4sYb7d8b2jSCM_qto48-6451rbyEhXXywtFy_JqtTpbsw_IIdQHMr1O-MdSjsQxX9kkvZwPU8LsC-CcqlcsZ7mnpOhmIXaf4tbRwAaluXwYft0yykFsp8e5C4t9mMs9Vu8AB5gT8o-D_ovXd2qh4k3ejzVpYLtzD4nbfvPJA_TXmjhn-9GOPAqkzfON2Q\"}]}";
@@ -194,6 +196,12 @@ public class NimbusJwtDecoderTests {
// @formatter:on
}
@Test
public void decodeWhenTokenMalformedThenReturnsMalformedTokenMessage() {
assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> this.jwtDecoder.decode(MALFORMED_TOKEN))
.withMessage("An error occurred while attempting to decode the Jwt: Malformed token");
}
@Test
public void decodeWhenJwtFailsValidationThenReturnsCorrespondingErrorMessage() {
OAuth2Error failure = new OAuth2Error("mock-error", "mock-description", "mock-uri");
@@ -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 -1
View File
@@ -6,7 +6,7 @@ pluginManagement {
plugins {
id "com.gradle.enterprise" version "3.11.4"
id "io.spring.ge.conventions" version "0.0.14"
id "io.spring.ge.conventions" version "0.0.16"
}
dependencyResolutionManagement {
@@ -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;
@@ -122,7 +122,7 @@ public final class XXssProtectionHeaderWriter implements HeaderWriter {
* specify mode as blocked. The content will be replaced with "#". For example:
*
* <pre>
* X-XSS-Protection: 1 ; mode=block
* X-XSS-Protection: 1; mode=block
* </pre>
* @param headerValue the new header value
* @throws IllegalArgumentException when headerValue is null
@@ -134,7 +134,7 @@ public final class XXssProtectionHeaderWriter implements HeaderWriter {
}
/**
* The value of the x-xss-protection header. One of: "0", "1", "1 ; mode=block"
* The value of the x-xss-protection header. One of: "0", "1", "1; mode=block"
*
* @author Daniel Garnier-Moiroux
* @since 5.8
@@ -122,7 +122,7 @@ public class XXssProtectionServerHttpHeadersWriter implements ServerHttpHeadersW
* specify mode as blocked. The content will be replaced with "#". For example:
*
* <pre>
* X-XSS-Protection: 1 ; mode=block
* X-XSS-Protection: 1; mode=block
* </pre>
* @param headerValue the new headerValue
* @throws IllegalArgumentException if headerValue is null
@@ -135,14 +135,14 @@ public class XXssProtectionServerHttpHeadersWriter implements ServerHttpHeadersW
}
/**
* The value of the x-xss-protection header. One of: "0", "1", "1 ; mode=block"
* The value of the x-xss-protection header. One of: "0", "1", "1; mode=block"
*
* @author Daniel Garnier-Moiroux
* @since 5.8
*/
public enum HeaderValue {
DISABLED("0"), ENABLED("1"), ENABLED_MODE_BLOCK("1 ; mode=block");
DISABLED("0"), ENABLED("1"), ENABLED_MODE_BLOCK("1; mode=block");
private final String value;
@@ -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.
@@ -782,6 +782,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");
@@ -49,7 +49,7 @@ public class XXssProtectionServerHttpHeadersWriterTests {
this.writer.writeHttpHeaders(this.exchange);
assertThat(this.headers).hasSize(1);
assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION))
.containsOnly("1 ; mode=block");
.containsOnly("1; mode=block");
}
@Test
@@ -99,7 +99,7 @@ public class XXssProtectionServerHttpHeadersWriterTests {
this.writer.writeHttpHeaders(this.exchange);
assertThat(this.headers).hasSize(1);
assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION))
.containsOnly("1 ; mode=block");
.containsOnly("1; mode=block");
}
}