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

Compare commits

..

148 Commits

Author SHA1 Message Date
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
dependabot[bot] bb0987db80 Bump org.springframework.data:spring-data-bom
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2021.2.17 to 2021.2.18.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2021.2.17...2021.2.18)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-20 08:51:36 -03:00
Josh Cummings d961307044 Polish RequestMatcher Description
Issue gh-13794
2023-11-17 12:24:38 -07:00
Josh Cummings 4ca54683ae Defer requestMatchers Validation to Runtime
Closes gh-13794
2023-11-17 11:23:21 -07:00
Marcus Hert Da Coregio a7da9491d9 Use assertj assertions 2023-11-17 09:03:36 -03:00
dependabot[bot] 382cfd63ed Bump io-spring-javaformat from 0.0.39 to 0.0.40
Bumps `io-spring-javaformat` from 0.0.39 to 0.0.40.

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

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

---
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>
2023-11-17 09:03:36 -03:00
dependabot[bot] 7c98a39770 Bump org.springframework:spring-framework-bom from 5.3.30 to 5.3.31
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 5.3.30 to 5.3.31.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.30...v5.3.31)

---
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>
2023-11-17 09:03:29 -03:00
dependabot[bot] 6afcc02ef3 Bump io.projectreactor:reactor-bom from 2020.0.37 to 2020.0.38
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2020.0.37 to 2020.0.38.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2020.0.37...2020.0.38)

---
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-11-16 08:35:55 -03:00
dependabot[bot] 773673ac2c Bump io.projectreactor.netty:reactor-netty from 1.0.38 to 1.0.39
Bumps [io.projectreactor.netty:reactor-netty](https://github.com/reactor/reactor-netty) from 1.0.38 to 1.0.39.
- [Release notes](https://github.com/reactor/reactor-netty/releases)
- [Commits](https://github.com/reactor/reactor-netty/compare/v1.0.38...v1.0.39)

---
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-11-16 08:35:05 -03:00
Steve Riesenberg 7335c5745c Document authentication helper method in WebClient integration
This commit re-applies 49f3c0ce53
which was lost while splitting pages for Antora.

Issue gh-13816
Issue gh-10120
2023-11-09 10:46:32 -06:00
Josh Cummings 52675c80b3 Check For Null Exception Message
Closes gh-13768
2023-11-07 17:19:35 -07:00
Josh Cummings b919ece045 Change Idempotent to Read-Only
Closes gh-13644
2023-11-07 16:25:28 -07:00
Josh Cummings 11a21896dd Defer SecurityContextHolderStrategy Lookup
Due to how early method interceptors are loaded during startup
it's reasonable to consider scenarios where applications are
changing the global security context holder strategy during
startup.

Closes gh-12877
2023-11-07 12:36:16 -07:00
Marcus Hert Da Coregio eff9814d7b Add links to WebFlux section where referenced
Closes gh-14100
2023-11-07 13:13:41 -03:00
Dong, Xue-Han 058495d463 Add the Authorization Section to Nav List
Closes gh-14099
2023-11-07 13:11:52 -03:00
Josh Cummings ffd12ee3b9 Refine requestMatcher Validation Rules
Closes gh-14078
2023-10-31 17:08:24 -06:00
Marcus Hert Da Coregio 3f64c6d745 Use version catalog to resolve nimbus dependency versions
Issue gh-14047
2023-10-30 16:11:51 -03:00
Marcus Hert Da Coregio 2cd302fb1b Revert "Use lenient configuration for prohibited dependencies check"
This reverts commit 602d4189d1.
2023-10-30 16:11:02 -03:00
Marcus Hert Da Coregio e8ec49b4c5 Resolve versions without downloading dependencies
Issue gh-14047
2023-10-30 14:46:12 -03:00
Marcus Hert Da Coregio 602d4189d1 Use lenient configuration for prohibited dependencies check
Issue gh-14047
2023-10-30 12:10:32 -03:00
Marcus Hert Da Coregio 884014c2fb Use lenient configuration to resolve artifacts
Issue gh-14047
2023-10-30 11:25:30 -03:00
Marcus Hert Da Coregio 47969ec7c9 Fix verifyDependenciesVersions not working with s101
Issue gh-14047
2023-10-30 08:28:15 -03:00
Marcus Da Coregio 6654479649 Polish VerifyDependenciesVersionsPlugin
Issue gh-14047
2023-10-27 09:45:19 -03:00
Steve Riesenberg bfc31bacab Polish Username/Password Authentication page
Issue gh-11926

(cherry picked from commit 781d575921)
2023-10-25 15:50:53 -05:00
Marcus Da Coregio ad2bea3350 Fail build if nimbus-jose-jwt version is not aligned
Closes gh-14047
2023-10-25 13:44:23 -03:00
Steve Riesenberg 5161712c35 Polish gh-13976
Closes gh-13757
2023-10-19 16:40:23 -05:00
Veli Döngelci a6b872dcf3 Fix caching error state in ReactiveRemoteJWKSource 2023-10-19 16:40:13 -05:00
Marcus Da Coregio 70ad3bf749 relay_state should not be included in signing calculation when it is null
Closes gh-13913
2023-10-19 09:58:47 -03:00
Scott Shidlovsky 19c4e427ee Update OpenSamlAuthenticationRequestResolverTests from Junit 4 to Junit 5
(cherry picked from commit 508f7d7b8a)
2023-10-19 09:50:28 -03:00
Marcus Da Coregio 736f1c27cd Remove updateDependencies plugin
Closes gh-13966
2023-10-18 14:12:25 -03:00
github-actions[bot] ec58bf0b28 Next development version 2023-10-16 16:06:01 +00:00
github-actions[bot] e4e31f2c90 Release 5.8.8 2023-10-16 15:21:39 +00:00
dependabot[bot] 49cd8ae217 Bump org.springframework.data:spring-data-bom
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2021.2.16 to 2021.2.17.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2021.2.16...2021.2.17)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 07:48:24 -03:00
Steve Riesenberg 81d91063a5 Document how to publish an AuthenticationManager
Closes gh-11926
2023-10-13 18:15:09 -05:00
dependabot[bot] 7f50bb5db1 Bump io.projectreactor.netty:reactor-netty from 1.0.36 to 1.0.38
Bumps [io.projectreactor.netty:reactor-netty](https://github.com/reactor/reactor-netty) from 1.0.36 to 1.0.38.
- [Release notes](https://github.com/reactor/reactor-netty/releases)
- [Commits](https://github.com/reactor/reactor-netty/compare/v1.0.36...v1.0.38)

---
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-10-11 07:58:11 -03:00
dependabot[bot] 7556df6ea7 Bump io.projectreactor:reactor-bom from 2020.0.36 to 2020.0.37
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2020.0.36 to 2020.0.37.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2020.0.36...2020.0.37)

---
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-10-11 07:56:17 -03:00
dependabot[bot] 71ceb5b80b Bump org-eclipse-jetty from 9.4.52.v20230823 to 9.4.53.v20231009
Bumps `org-eclipse-jetty` from 9.4.52.v20230823 to 9.4.53.v20231009.

Updates `org.eclipse.jetty:jetty-server` from 9.4.52.v20230823 to 9.4.53.v20231009
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.52.v20230823...jetty-9.4.53.v20231009)

Updates `org.eclipse.jetty:jetty-servlet` from 9.4.52.v20230823 to 9.4.53.v20231009
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.52.v20230823...jetty-9.4.53.v20231009)

---
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>
2023-10-11 07:56:06 -03:00
dependabot[bot] bd9643af44 Bump com.github.spullara.mustache.java:compiler from 0.9.10 to 0.9.11
Bumps [com.github.spullara.mustache.java:compiler](https://github.com/spullara/mustache.java) from 0.9.10 to 0.9.11.
- [Commits](https://github.com/spullara/mustache.java/compare/0.9.10...mustache.java-0.9.11)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-10 08:20:03 -03:00
dependabot[bot] d46627b776 Bump org.jfrog.buildinfo:build-info-extractor-gradle
Bumps [org.jfrog.buildinfo:build-info-extractor-gradle](https://github.com/jfrog/build-info) from 4.29.0 to 4.29.4.
- [Release notes](https://github.com/jfrog/build-info/releases)
- [Changelog](https://github.com/jfrog/build-info/blob/master/RELEASE.md)
- [Commits](https://github.com/jfrog/build-info/compare/build-info-gradle-extractor-4.29.0...build-info-gradle-extractor-4.29.4)

---
updated-dependencies:
- dependency-name: org.jfrog.buildinfo:build-info-extractor-gradle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 07:29:32 -03:00
dependabot[bot] 8c6b5e0efe Bump io.spring.ge.conventions from 0.0.7 to 0.0.14
Bumps [io.spring.ge.conventions](https://github.com/spring-io/gradle-enterprise-conventions) from 0.0.7 to 0.0.14.
- [Release notes](https://github.com/spring-io/gradle-enterprise-conventions/releases)
- [Commits](https://github.com/spring-io/gradle-enterprise-conventions/compare/v0.0.7...v0.0.14)

---
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>
2023-10-04 09:29:32 -03:00
dependabot[bot] 3315775734 Bump org.apache.logging.log4j:log4j-core from 2.17.1 to 2.17.2
Bumps org.apache.logging.log4j:log4j-core from 2.17.1 to 2.17.2.

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-04 09:27:24 -03:00
dependabot[bot] cefcbdc819 Bump com.github.spullara.mustache.java:compiler from 0.9.4 to 0.9.10
Bumps [com.github.spullara.mustache.java:compiler](https://github.com/spullara/mustache.java) from 0.9.4 to 0.9.10.
- [Commits](https://github.com/spullara/mustache.java/compare/mustache.java-0.9.4...0.9.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-04 09:27:08 -03:00
dependabot[bot] 0b25dc53cc Bump com.gradle.enterprise from 3.11.1 to 3.11.4
Bumps com.gradle.enterprise from 3.11.1 to 3.11.4.

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-04 09:26:54 -03:00
dependabot[bot] 766396aa7c Bump io.projectreactor:reactor-bom from 2020.0.35 to 2020.0.36
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2020.0.35 to 2020.0.36.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2020.0.35...2020.0.36)

---
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-10-04 09:26:23 -03:00
Marcus Da Coregio 64270f28e4 Saml2LogoutRequestMixin relayState property should be binding
Closes gh-12539
2023-10-03 08:41:33 -03:00
dependabot[bot] ece5089cc8 Bump org-aspectj from 1.9.20 to 1.9.20.1
Bumps `org-aspectj` from 1.9.20 to 1.9.20.1.

Updates `org.aspectj:aspectjrt` from 1.9.20 to 1.9.20.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 to 1.9.20.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>
2023-10-02 15:09:50 -03:00
dependabot[bot] 448d23dd3e Bump org.springframework.data:spring-data-bom
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2021.2.15 to 2021.2.16.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2021.2.15...2021.2.16)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-02 15:09:34 -03:00
dependabot[bot] 0108241049 Bump org.springframework:spring-framework-bom from 5.3.29 to 5.3.30
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 5.3.29 to 5.3.30.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.29...v5.3.30)

---
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>
2023-10-02 15:09:13 -03:00
dependabot[bot] 88cfae4182 Bump org-eclipse-jetty from 9.4.51.v20230217 to 9.4.52.v20230823
Bumps `org-eclipse-jetty` from 9.4.51.v20230217 to 9.4.52.v20230823.

Updates `org.eclipse.jetty:jetty-server` from 9.4.51.v20230217 to 9.4.52.v20230823
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.51.v20230217...jetty-9.4.52.v20230823)

Updates `org.eclipse.jetty:jetty-servlet` from 9.4.51.v20230217 to 9.4.52.v20230823
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.51.v20230217...jetty-9.4.52.v20230823)

---
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>
2023-10-02 15:08:47 -03:00
Marcus Da Coregio b9836d618a Fix Workflows
Issue gh-13873
2023-09-29 15:50:10 -03:00
Marcus Da Coregio 2505c08e8f Do Not Run Some Workflows on Dependabot's PRs
Issue gh-13873

(cherry picked from commit 3aae03b1b2)
2023-09-29 15:48:12 -03:00
Marcus Da Coregio 9e877c9bc6 Do not run some workflows for Dependabot branches
Issue gh-13873

(cherry picked from commit ab812b2b53)
2023-09-29 15:48:11 -03:00
dependabot[bot] adef0f3f25 Bump com.google.code.gson:gson from 2.8.6 to 2.8.9
Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.8.6 to 2.8.9.
- [Release notes](https://github.com/google/gson/releases)
- [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/gson/compare/gson-parent-2.8.6...gson-parent-2.8.9)

---
updated-dependencies:
- dependency-name: com.google.code.gson:gson
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-29 14:19:16 -03:00
dependabot[bot] a8eb565b05 Bump io.projectreactor.netty:reactor-netty from 1.0.35 to 1.0.36
Bumps [io.projectreactor.netty:reactor-netty](https://github.com/reactor/reactor-netty) from 1.0.35 to 1.0.36.
- [Release notes](https://github.com/reactor/reactor-netty/releases)
- [Commits](https://github.com/reactor/reactor-netty/compare/v1.0.35...v1.0.36)

---
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-09-29 14:14:00 -03:00
Marcus Da Coregio 64e2a2ff8b Apply updated Code Style
Closes gh-13881
2023-09-29 11:44:32 -03:00
Marcus Da Coregio 650692964e Fix snapshot_tests on CI workflow
Closes gh-13876
2023-09-28 15:58:43 -03:00
Marcus Da Coregio e29ea47ff7 Use Gradle's Version Catalog
Issue gh-13868
2023-09-28 14:57:18 -03:00
Marcus Da Coregio 664ee9a206 Fix formatting
Issue gh-13776
2023-09-25 10:09:32 -03:00
Jannick Weisshaupt b67218c150 Fix corrupted saml2 metadata when special characters are present
Closes gh-13776
2023-09-25 14:08:14 +01:00
Eric Haag ac04c2e675 Add dependency between rncToXsd and sourcesJar
Since processResources is configured directly instead of via the source
set container, an explicit dependency task between rncToXsd and
sourcesJar must be defined.

Issue gh-13845
2023-09-19 14:19:45 +01:00
Eric Haag e63d7fd9e9 Add dependency between rncToXsd and versionlessXsd
Since processResources is configured directly instead of via the source
set container, an explicit dependency task between rncToXsd and
versionlessXsd must be defined.

Issue gh-13845
2023-09-19 14:19:33 +01:00
Eric Haag 718c470910 Prevent creating duplicate .xsd entries
This change removes .xsd entries that would appear in the top level of
the assembled artifacts. This occurred because the output of the
rncToXsd task does not consider the path beneath the resources
directory. To fix this, the processResources task is directly
configured with a copy spec so the required path can be set.

Issue gh-13845
2023-09-19 14:19:19 +01:00
Steve Riesenberg 700b711c4b Merge branch '5.7.x' into 5.8.x 2023-09-18 11:22:40 -05:00
github-actions[bot] c614422f44 Next development version 2023-09-18 16:10:51 +00:00
github-actions[bot] 85e0783796 Next development version 2023-09-18 16:10:25 +00:00
github-actions[bot] 3656fa6e0c Release 5.7.11 2023-09-18 15:24:51 +00:00
github-actions[bot] 564a022ab6 Release 5.8.7 2023-09-18 15:22:27 +00:00
Rob Winch 779541b340 Merge branch '5.7.x' into 5.8.x
Automate spring-security.xsd

Closes gh-13823
2023-09-14 23:37:53 -05:00
Rob Winch 5b293d2116 Automate spring-security.xsd
Closes gh-13819
2023-09-14 16:01:50 -05:00
Eric Haag f026e29771 Add dependency on rncToXsd task from nohttp
This addresses a deprecation warning causing build caching to be
disabled for the checkstyleNohttp task. With this change, we tell
Gradle that the rncToXsd task in the spring-security-config project
produces output that should be considered when running the
checkstyleNohttp task. This clears up ambiguities when computing the
task graph.
2023-09-13 13:58:44 +01:00
Eric Haag 620e6e0c34 Add rncToXsd task to resources set
This addresses a deprecation warning causing build caching to be
disabled for some tasks. With this change, we tell Gradle that the
rncToXsd task produces output that should be considered a resource.
This clears up ambiguities when computing the task graph.
2023-09-13 13:58:42 +01:00
Eric Haag 4ebfa2c804 Use lazy API to configure rncToXsd task
This avoids configuring the task eagerly.
2023-09-13 13:58:05 +01:00
Steve Riesenberg 3feb809b35 Fix Saml2AuthenticationExceptionMixin on JDK 17
Closes gh-13804
2023-09-12 18:39:29 -05:00
Steve Riesenberg 9b7a110704 Fix OAuth2AuthenticationExceptionMixinTests on JDK 17
Closes gh-11893
2023-09-12 16:51:47 -05:00
Marcus Da Coregio ce012a4661 CookieRequestCache Should Preserve Request Locale
Closes gh-13792
2023-09-12 16:21:27 +01:00
Marcus Da Coregio 96d1763fc4 WWW-Authenticate header should not be added twice
Closes gh-13737
2023-08-31 10:07:10 -03:00
github-actions[bot] 8efbbb3eb5 Next development version 2023-08-21 16:09:41 +00:00
github-actions[bot] 612909ac4f Release 5.8.6 2023-08-21 15:21:12 +00:00
Josh Cummings 28f98b3351 Improve Error Message
Closes gh-13667
2023-08-20 22:53:57 -06:00
Josh Cummings ed96e2cddf Ignore Unmappable Servlets
Closes gh-13666
2023-08-20 22:53:55 -06:00
Steve Riesenberg 7200f76ac1 Update org.springframework.data to 2021.2.15
Closes gh-13705
2023-08-18 15:58:36 -05:00
Steve Riesenberg 094b71b329 Update org.aspectj to 1.9.20
Closes gh-13704
2023-08-18 15:58:33 -05:00
Steve Riesenberg 491f0f647c Update io.projectreactor to 2020.0.35
Closes gh-13702
2023-08-18 15:58:27 -05:00
Mario Petrovski 1db8734101 Closes #11450 Add Java beans configuration for Remmember Me Docs 2023-08-09 09:54:53 -03:00
Kawin Naipongprasit 4b44a2d924 Adapeter to Adapter 2023-08-07 15:25:47 -06:00
Daniel Shuy e8b9a35494 Fix Bearer Token RestTemplate Support example 2023-08-07 14:47:37 -06:00
Rob Winch 82e5f62079 Use includeGroupByRegex
This makes the include more robust

Issue gh-13582
2023-08-07 10:26:57 -05:00
Eric Haag 30bc2634d7 Optimize configuration of project repositories
This change applies repository content filtering to configured
repositories, reducing the time spent during dependency resolution.

This fixes an issue where requests for 'org.opensaml',
'net.shibboleth.utilities' and 'net.minidev' dependencies were being
made in the Spring releases repositories, resulting in many failed
requests during dependency resolution and increased resolution times.

Closes gh-13582
2023-08-07 09:51:42 -05:00
Marcus Da Coregio 13ca7ac4d4 Referrer-Policy is added by default in Reactive applications
Closes gh-13561
2023-07-27 11:22:21 -03:00
Josh Cummings c4f061c63d Do Not Re-register Method Security Advisors
Closes gh-13572
2023-07-24 11:24:03 -06:00
Marcus Da Coregio 2c6d053ceb Merge branch '5.7.x' into 5.8.x 2023-07-18 09:51:45 -03:00
Marcus Da Coregio ff4745a461 Merge branch '5.6.x' into 5.7.x 2023-07-18 09:51:19 -03:00
github-actions[bot] 38a7ffcc9b Next development version 2023-07-17 21:52:14 +00:00
github-actions[bot] 6f55fc60bb Next development version 2023-07-17 21:46:35 +00:00
github-actions[bot] d0491c07e9 Next development version 2023-07-17 21:42:28 +00:00
github-actions[bot] 486c5118d2 Release 5.7.10 2023-07-17 21:05:15 +00:00
github-actions[bot] d02ab50577 Release 5.8.5 2023-07-17 21:04:33 +00:00
github-actions[bot] 17d8293be1 Release 5.6.12 2023-07-17 21:00:49 +00:00
Josh Cummings bb46a54270 Add DispatcherServlet to Tests
Issue gh-13551
2023-07-17 10:58:30 -06:00
Josh Cummings df239b6448 Improve RequestMatcher Validation
Closes gh-13551
2023-07-17 08:41:30 -06:00
Marcus Da Coregio a939f17890 Merge branch '5.7.x' into 5.8.x 2023-07-17 09:15:56 -03:00
Marcus Da Coregio fe9bc26bdc Merge branch '5.6.x' into 5.7.x 2023-07-17 09:13:28 -03:00
Marcus Da Coregio 7813a9ba26 Use default PathPatternParser instance 2023-07-17 09:12:28 -03:00
Marcus Da Coregio 7d58b9391a Merge branch '5.7.x' into 5.8.x 2023-07-14 11:04:26 -03:00
Marcus Da Coregio dc3cb68c76 Merge branch '5.6.x' into 5.7.x
Closes gh-dry-run
2023-07-14 11:04:01 -03:00
Marcus Da Coregio 8555c100d7 Update org.springframework.data to 2021.2.14
Closes gh-13516
2023-07-14 10:53:12 -03:00
Marcus Da Coregio ae46531add Update org.springframework to 5.3.29
Closes gh-13515
2023-07-14 10:53:08 -03:00
Marcus Da Coregio 0121b08a85 Update io.projectreactor to 2020.0.34
Closes gh-13513
2023-07-14 10:53:01 -03:00
Marcus Da Coregio 56292c9971 Update org.springframework.data to 2021.2.14
Closes gh-13512
2023-07-14 10:52:14 -03:00
Marcus Da Coregio 4fc938555e Update org.springframework to 5.3.29
Closes gh-13511
2023-07-14 10:52:11 -03:00
Marcus Da Coregio e574415244 Update io.projectreactor to 2020.0.34
Closes gh-13509
2023-07-14 10:52:03 -03:00
Marcus Da Coregio c5da886310 Update org.springframework to 5.3.29
Closes gh-13508
2023-07-14 10:42:27 -03:00
Marcus Da Coregio 3bef5fd3ed Update io.projectreactor to 2020.0.34
Closes gh-13505
2023-07-14 10:42:27 -03:00
Steve Riesenberg b7a9a654f0 Merge branch '5.7.x' into 5.8.x 2023-07-12 16:06:02 -05:00
Steve Riesenberg e7201c48d1 Fix copy/paste from main
Issue gh-13500
2023-07-12 16:04:35 -05:00
Steve Riesenberg a642fdb004 Merge branch '5.7.x' into 5.8.x 2023-07-12 15:52:55 -05:00
Steve Riesenberg 991b398c55 Create release with full docs path
Closes gh-13500
2023-07-12 15:51:44 -05:00
Josh Cummings 40d61743b9 Replace Existing Continue Parameter
Closes gh-13438
2023-07-10 16:12:05 -06:00
Josh Cummings 8895a66a2b Add hasIpAddress Migration Steps
Closes gh-13474
2023-07-10 13:35:16 -06:00
Marcus Da Coregio 80a5028f3f saml2Login filterProcessingUrl should be loginProcessingUrl
Closes gh-13417
2023-06-23 10:38:04 -03:00
Marcus Da Coregio c30bacac10 Improve Security Filters Documentation
Closes gh-8167
2023-06-22 10:11:18 -03:00
Marcus Da Coregio a104dec30d Merge branch '5.7.x' into 5.8.x 2023-06-19 14:18:50 -03:00
Marcus Da Coregio 488b6ea531 Merge branch '5.6.x' into 5.7.x 2023-06-19 14:18:23 -03:00
github-actions[bot] ef04ea9d68 Next development version 2023-06-19 17:05:13 +00:00
github-actions[bot] b7be4c462c Next development version 2023-06-19 16:55:18 +00:00
Marcus Da Coregio aa8440e1ee Release 5.6.11 2023-06-19 13:23:20 -03:00
github-actions[bot] 6d3f1699c0 Release 5.7.9 2023-06-19 16:09:53 +00:00
github-actions[bot] bb72eed8d1 Next development version 2023-06-19 16:02:54 +00:00
github-actions[bot] 108075763b Release 5.8.4 2023-06-19 15:21:27 +00:00
2385 changed files with 53668 additions and 53388 deletions
-4
View File
@@ -7,10 +7,6 @@ assignees: ''
---
<!--
Do NOT report Security Vulnerabilities here. Please use https://github.com/spring-projects/spring-security/security/policy
-->
**Describe the bug**
A clear and concise description of what the bug is.
@@ -2,8 +2,8 @@ name: CI
on:
push:
branches:
- '**'
branches-ignore:
- "dependabot/**"
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
@@ -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: |
@@ -40,8 +40,8 @@ jobs:
# Extract version from gradle.properties
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
echo "project_version=$version" >>$GITHUB_OUTPUT
build_jdk_17:
name: Build JDK 17
build_jdk_11:
name: Build JDK 11
needs: [prerequisites]
strategy:
matrix:
@@ -49,12 +49,12 @@ jobs:
runs-on: ${{ matrix.os }}
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
cache: 'gradle'
- name: Set up Gradle
uses: gradle/gradle-build-action@v2
@@ -72,30 +72,30 @@ 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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- name: Snapshot Tests
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew test --refresh-dependencies -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" -PforceMavenRepositories=snapshot -PspringVersion='5.+' -PreactorVersion='20+' -PspringDataVersion='Neumann-BUILD-SNAPSHOT' -PrsocketVersion=1.1.0-SNAPSHOT -PspringBootVersion=2.4.0-SNAPSHOT -PlocksDisabled --stacktrace
./gradlew test --refresh-dependencies -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PspringFrameworkVersion='5.+' -PreactorVersion='2020.0.+' -PspringDataVersion='2021.2.+' -PlocksDisabled --stacktrace
check_samples:
name: Check Samples project
needs: [prerequisites]
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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- name: Check samples project
env:
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
@@ -114,12 +114,12 @@ 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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- name: Check for package tangles
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
@@ -128,15 +128,15 @@ jobs:
./gradlew check s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace
deploy_artifacts:
name: Deploy Artifacts
needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles]
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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- name: Deploy artifacts
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
@@ -152,15 +152,15 @@ jobs:
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
deploy_docs:
name: Deploy Docs
needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles]
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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- name: Deploy Docs
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
@@ -173,15 +173,15 @@ jobs:
DOCS_HOST: ${{ secrets.DOCS_HOST }}
deploy_schema:
name: Deploy Schema
needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles]
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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- name: Deploy Schema
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
@@ -206,14 +206,14 @@ 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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- name: Wait for Artifactory Artifacts
if: ${{ contains(needs.prerequisites.outputs.project_version, '-RC') || contains(needs.prerequisites.outputs.project_version, '-M') }}
run: |
@@ -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.24.0
with:
payload: |
{
@@ -287,12 +287,12 @@ 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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- name: Schedule next release (if not already scheduled)
run: ./gradlew scheduleNextRelease -PnextVersion=$VERSION -PgitHubAccessToken=$TOKEN
notify_result:
+6 -4
View File
@@ -1,12 +1,14 @@
name: Deploy Docs
on:
push:
branches-ignore: [ gh-pages ]
branches-ignore:
- "gh-pages"
- "dependabot/**"
tags: '**'
repository_dispatch:
types: request-build-reference # legacy
#schedule:
#- cron: '0 10 * * *' # Once per day at 10am UTC
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch:
permissions: read-all
jobs:
@@ -15,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
@@ -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.2.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
+9 -4
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,11 +16,11 @@ 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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- name: Build with Gradle
run: ./gradlew clean build --continue --scan
-24
View File
@@ -1,24 +0,0 @@
name: Release Scheduler
on:
schedule:
- cron: '15 15 * * MON' # Every Monday at 3:15pm UTC
workflow_dispatch:
permissions: read-all
jobs:
dispatch_scheduled_releases:
name: Dispatch scheduled releases
if: github.repository_owner == 'spring-projects'
strategy:
matrix:
# List of active maintenance branches.
branch: [ main, 6.0.x, 5.8.x, 5.7.x ]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 1
- name: Dispatch
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run update-scheduled-release-version.yml -r ${{ matrix.branch }}
@@ -23,14 +23,14 @@ 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: '17'
distribution: 'temurin'
java-version: '11'
distribution: 'adopt'
- id: check-release-due
name: Check Release Due
run: |
@@ -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.2.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
+1 -1
View File
@@ -3,4 +3,4 @@
# See https://sdkman.io/usage#config
# A summary is to add the following to ~/.sdkman/etc/config
# sdkman_auto_env=true
java=17.0.3-tem
java=11.0.14-tem
-3
View File
@@ -1,3 +0,0 @@
{
"java.import.gradle.enabled": false
}
+196 -118
View File
@@ -1,154 +1,232 @@
= Contributing to Spring Security
_Have something you'd like to contribute to the framework? We welcome pull requests, but ask that you carefully read this document first to understand how best to submit them; what kind of changes are likely to be accepted; and what to expect from the Spring Security team when evaluating your submission._
First off, thank you for taking the time to contribute! :+1: :tada:
_Please refer back to this document as a checklist before issuing any pull request; this will save time for everyone!_
== Table of Contents
= Code of Conduct
* <<code-of-conduct>>
* <<how-to-contribute>>
* <<ask-questions>>
* <<find-an-issue>>
* <<create-an-issue>>
* <<issue-lifecycle>>
* <<submit-a-pull-request>>
* <<build-from-source>>
* <<code-style>>
Please see our https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[code of conduct].
[[code-of-conduct]]
== Code of Conduct
= Similar but different
This project is governed by the https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[Spring code of conduct].
By participating you are expected to uphold this code.
Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
Each Spring module is slightly different from one another in terms of team size, number of issues, etc. Therefore, each project is managed slightly different. You will notice that this document is very similar to the https://github.com/spring-projects/spring-framework/wiki/Contributor-guidelines[Spring Framework Contributor guidelines]. However, there are some subtle differences between the two documents, so please be sure to read this document thoroughly.
[[how-to-contribute]]
== How to Contribute
= Importing into IDE
[[ask-questions]]
=== Ask Questions
The following provides information on setting up a development environment that can run the sample in https://www.springsource.org/sts[Spring Tool Suite 3.6.0+]. Other IDE's should work using Gradle's IDE support, but have not been tested.
If you have a question, check Stack Overflow using
https://stackoverflow.com/questions/tagged/spring-security+or+spring-ldap+or+spring-authorization-server+or+spring-session?tab=Newest[this list of tags].
Find an existing discussion, or start a new one if necessary.
* IDE Setup
** Install Spring Tool Suite 3.6.0+
** You will need the following plugins installed (can be found on the Extensions Page)
*** Gradle Eclipse
*** Groovy Eclipse
* Importing the project into Spring Tool Suite
** File -> Import… -> Gradle Project
If you believe there is an issue, search through https://github.com/spring-projects/spring-security/issues[existing issues] trying a few different ways to find discussions, past or current, that are related to the issue.
Reading those discussions helps you to learn about the issue, and helps us to make a decision.
As of new versions of Spring Tool Suite, you might need to install Groovy Eclipse pointing directly to the updated plugin location. To install Groovy Eclipse on Spring Tool Suite based on Eclipse Oxigen you must do the following steps:
[[find-an-issue]]
=== Find an Existing Issue
Help -> Install New Software… -> Add the following URL into _Work with_ field:
https://dist.springsource.org/snapshot/GRECLIPSE/e4.7/[https://dist.springsource.org/snapshot/GRECLIPSE/e4.7/]
There are many issues in Spring Security with the labels https://github.com/spring-projects/spring-security/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+ideal-for-contribution%22[`ideal-for-contribution`] or https://github.com/spring-projects/spring-security/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+first-timers-only%22[`first-timers-only`] that are a great way to contribute to a discussion or <<submit-a-pull-request,to a PR>>.
You can volunteer by commenting on these tickets, and we will assign them to you.
= Understand the basics
[[create-an-issue]]
=== Create an Issue
Not sure what a pull request is, or how to submit one? Take a look at GitHub's excellent https://help.github.com/articles/using-pull-requests[help documentation first].
Reporting an issue or making a feature request is a great way to contribute.
Your feedback and the conversations that result from it provide a continuous flow of ideas.
However, before creating a ticket, please take the time to <<ask-questions,ask and research>> first.
= Search GitHub issues; create an issue if necessary
If you create an issue after a discussion on Stack Overflow, please provide a description in the issue instead of simply referring to Stack Overflow.
The issue tracker is an important place of record for design discussions and should be self-sufficient.
Is there already an issue that addresses your concern? Do a bit of searching in our https://github.com/spring-projects/spring-security/issues[GitHub issues] to see if you can find something similar. If not, please create a new issue before submitting a pull request unless the change is not a user facing issue.
Once you're ready, create an issue on https://github.com/spring-projects/spring-security/issues[GitHub].
= Discuss non-trivial contribution ideas with committers
Many issues are caused by subtle behavior, typos, and unintended configuration.
Creating a https://stackoverflow.com/help/minimal-reproducible-example[Minimal Reproducible Example] (starting with https://start.spring.io for example) of the problem helps the team quickly triage your issue and get to the core of the problem.
If you're considering anything more than correcting a typo or fixing a minor bug, please discuss it on the https://gitter.im/spring-projects/spring-security[Spring Security Gitter] before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
We love contributors, and we may ask you to <<submit-a-pull-request,submit a PR with a fix>>.
= Sign the Contributor License Agreement
[[issue-lifecycle]]
=== Issue Lifecycle
If you have not previously done so, please fill out and submit the https://cla.pivotal.io/sign/spring[Contributor License Agreement].
When an issue is first created, it is flagged `waiting-for-triage` waiting for a team member to triage it.
Once the issue has been reviewed, the team may ask for further information if needed, and based on the findings, the issue is either assigned a target branch (or no branch if a feature) or is closed with a specific status.
The target branch is https://spring.io/projects/spring-security#support[the earliest supported branch] where <<choose-a-branch,the change will be applied>>.
= Create your branch from oldest maintenance branch
When a fix is ready, the issue is closed and may still be re-opened until the fix is released.
After that the issue will typically no longer be reopened.
In rare cases if the issue was not at all fixed, the issue may be re-opened.
In most cases however any follow-up reports will need to be created as new issues with a fresh description.
Create your topic branch to be submitted as a pull request from the oldest impacted and supported maintenance branch.
You can find the supported versions by looking at the https://github.com/spring-projects/spring-security/milestones[milestones page].
Switch to a branch named `<major>.<minor>.x` from the smallest milestone in the format of `<major>.<minor>.<patch>(-<prerelease>)`.
The spring team will ensure the code gets merged forward into additional branches.
[[build-from-source]]
=== Build from Source
= Use short branch names
See https://github.com/spring-projects/spring-security/tree/main#building-from-source[Build from Source] for instructions on how to check out, build, and import the Spring Security source code into your IDE.
Branches used when submitting pull requests should preferably be named according to GitHub issues, e.g. `gh-1234` or `gh-1234-fix-npe`. Otherwise, use succinct, lower-case, dash (`-`) delimited names, such as `fix-warnings` or `fix-typo`. This is important, because branch names show up in the merge commits that result from accepting pull requests, and should be as expressive and concise as possible.
[[code-style]]
=== Source Code Style
= Keep commits focused
The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize.
Remember each ticket should be focused on a single item of interest since the tickets are used to produce the changelog. Since each commit should be tied to a single GitHub issue, ensure that your commits are focused. For example, do not include an update to a transitive library in your commit unless the GitHub is to update the library. Reviewing your commits is essential before sending a pull request.
To format the code as well as check the style, run `./gradle format check`.
= Mind the whitespace
[[submit-a-pull-request]]
=== Submit a Pull Request
Please carefully follow the whitespace and formatting conventions already present in the framework.
We are excited for your pull request! :heart:
. Tabs, not spaces
. Unix (LF), not dos (CRLF) line endings
. Eliminate all trailing whitespace
. Aim to wrap code at 120 characters, but favor readability over wrapping
. Preserve existing formatting; i.e. do not reformat code for its own sake
. Search the codebase using `git grep` and other tools to discover common naming conventions, etc.
. UTF-8 encoding for Java sources and XML files
Please do your best to follow these steps.
Don't worry if you don't get them all correct the first time, we will help you.
Whitespace management tips
. You can use the https://marketplace.eclipse.org/content/anyedit-tools[AnyEdit Eclipse plugin] to ensure spaces are used and to clean up trailing whitespaces.
. Use Git's `pre-commit.sample` hook to prevent invalid whitespace from being pushed out. You can enable it by moving `.git/hooks/pre-commit.sample` to `.git/hooks/pre-commit` and ensuring it is executable. For more information on hooks refer to https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks[https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks].
= Add Apache license header to all new classes
[[sign-cla]]
1. If you have not previously done so, please sign the https://cla.spring.io/sign/spring[Contributor License Agreement].
You will be reminded automatically when you submit the PR.
[[create-an-issue]]
1. Must you https://github.com/spring-projects/spring-security/issues/new/choose[create an issue] first? No, but it is recommended for features and larger bug fixes. It's easier discuss with the team first to determine the right fix or enhancement.
For typos and straightforward bug fixes, starting with a pull request is encouraged.
Please include a description for context and motivation.
Note that the team may close your pull request if it's not a fit for the project.
[[choose-a-branch]]
1. Always check out the branch indicated in the milestone and submit pull requests against it (for example, for milestone `5.8.3` use the `5.8.x` branch).
If there is no milestone, choose `main`.
Once merged, the fix will be forwarded-ported to applicable branches including `main`.
[[create-a-local-branch]]
1. Create a local branch
If this is for an issue, consider a branch name with the issue number, like `gh-22276`.
[[write-tests]]
1. Add JUnit Tests for your changes
[[update-copyright]]
1. In all files you edited, if the copyright header is of the form 2002-20xx, update the final copyright year to the current year.
[[add-since]]
1. If on `main`, add `@since` JavaDoc attributes to new public APIs that your PR adds
[[change-rnc]]
1. If you are updating the XSD, please instead update the RNC file and then run `./gradlew :spring-security-config:rncToXsd`.
[[format-code]]
1. For each commit, build the code using `./gradlew format check`.
This command ensures the code meets most of <<code-style,the style guide>>; a notable exception is import order.
[[commit-atomically]]
1. Choose the granularity of your commits consciously and squash commits that represent
multiple edits or corrections of the same logical change.
See https://git-scm.com/book/en/Git-Tools-Rewriting-History[Rewriting History section of Pro Git] for an overview of streamlining the commit history.
[[format-commit-messages]]
1. Format commit messages using 55 characters for the subject line, 72 characters per line
for the description, followed by the issue fixed, for example, `Closes gh-22276`.
See the https://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project#Commit-Guidelines[Commit Guidelines section of Pro Git] for best practices around commit messages, and use `git log` to see some examples.
Present tense is preferred.
+
[indent=0]
----
Address NullPointerException
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Closes gh-22276
----
[[reference-issue]]
1. If there is a prior issue, reference the GitHub issue number in the description of the pull request.
+
[indent=0]
----
Closes gh-22276
package ...;
----
If accepted, your contribution may be heavily modified as needed prior to merging.
You will likely retain author attribution for your Git commits granted that the bulk of your changes remain intact.
You may also be asked to rework the submission.
= Update Apache license header to modified files as necessary
If asked to make corrections, simply push the changes against the same branch, and your pull request will be updated.
In other words, you do not need to create a new pull request when asked to make changes.
When it is time to merge, you'll be asked to squash your commits.
Always check the date range in the license header. For example, if you've modified a file in 2020 whose header still reads
==== Participate in Reviews
----
* Copyright 2002-2012 the original author or authors.
----
Helping to review pull requests is another great way to contribute.
Your feedback can help to shape the implementation of new features.
When reviewing pull requests, however, please refrain from approving or rejecting a PR unless you are a core committer for Spring Security.
then be sure to update it to the current year appropriately (e.g. 2020)
----
* Copyright 2002-2020 the original author or authors.
----
= Use @since tags for newly-added public API types and methods
Example:
----
/**
* …
*
* @author First Last
* @since 5.4
* @see …
*/
----
= Submit JUnit test cases for all behavior changes
Search the codebase to find related unit tests and add additional `@Test` methods within.
. Any new tests should end in the name `Tests` (note this is plural). For example, a valid name would be `FilterChainProxyTests`. An invalid name would be `FilterChainProxyTest`.
. New test methods should not start with test. This is an old JUnit3 convention and is not necessary since the method is annotated with `@Test`.
= Update spring-security-x.y.rnc for schema changes
Update the https://www.relaxng.org[RELAX NG] schema `spring-security-x.y.rnc` instead of `spring-security-x.y.xsd` if you contribute changes to supported XML configuration. The XML schema file can be generated the following Gradle task:
----
./gradlew :spring-security-config:rncToXsd
----
Changes to the XML schema will be overwritten by the Gradle build task.
= Squash commits
Use `git rebase --interactive`, `git add --patch` and other tools to "squash" multiple commits into atomic changes. In addition to the man pages for `git`, there are https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History[many resources online] to help you understand how these tools work.
= Use real name in git commits
Please configure Git to use your real first and last name for any commits you intend to submit as pull requests. Make sure the name is properly capitalized as submitted to the https://cla.pivotal.io[Pivotal Contributor License Agreement]:
----
First Last <user@mail.com>
----
This helps ensure traceability against the CLA, and also goes a long way to ensuring useful output from tools like Git shortlog and others.
You can configure this globally:
----
git config --global user.name "First Last"
git config --global user.email user@example.com
----
or locally for the current repository by omitting the `--global` flag:
----
git config user.name "First Last"
git config user.email user@example.com
----
= Format commit messages
. Keep the subject line to 50 characters or less if possible
. Do not end the subject line with a period
. In the body of the commit message, explain how things worked before this commit, what has changed, and how things work now
. Include `Closes gh-<issue-number>` at the end if this fixes a GitHub issue
. Avoid markdown, including back-ticks identifying code
Example:
----
Short (50 chars or less) summary of changes
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body. The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, preceded by a
single space, with blank lines in between, but conventions vary here
Closes gh-123
----
= Run all tests prior to submission
----
./gradlew clean build integrationTest
----
= Submit your pull request
*Subject line:*
Follow the same conventions for pull request subject lines as mentioned above for commit message subject lines.
*In the body:*
. Explain your use case. What led you to submit this change? Why were existing mechanisms in the framework insufficient? Make a case that this is a general-purpose problem and that yours is a general-purpose solution, etc
. Add any additional information and ask questions; start a conversation, or continue one from GitHub Issues
. Mention any GitHub Issues
. Also mention that you have submitted the CLA as described above
Note that for pull requests containing a single commit, GitHub will default the subject line and body of the pull request to match the subject line and body of the commit message. This is fine, but please also include the items above in the body of the request.
= Mention your pull request on the associated GitHub issue
Add a comment to the associated GitHub issue(s) linking to your new pull request.
= Expect discussion and rework
The Spring team takes a very conservative approach to accepting contributions to the framework. This is to keep code quality and stability as high as possible, and to keep complexity at a minimum. Your changes, if accepted, may be heavily modified prior to merging. You will retain "Author:" attribution for your Git commits granted that the bulk of your changes remain intact. You may be asked to rework the submission for style (as explained above) and/or substance. Again, we strongly recommend discussing any serious submissions with the Spring Framework team prior to engaging in serious development work.
Note that you can always force push (`git push -f`) reworked / rebased commits against the branch used to submit your pull request. i.e. you do not need to issue a new pull request when asked to make changes.
+8 -19
View File
@@ -6,8 +6,8 @@ image:https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?l
= Spring Security
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 6.0 requires Spring 6.0 as
a minimum and also requires Java 17.
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 5.0 requires Spring 5.0 as
a minimum and also requires Java 8.
For a detailed list of features and access to the latest release, please visit https://spring.io/projects[Spring projects].
@@ -30,9 +30,9 @@ In the instructions below, https://vimeo.com/34436402[`./gradlew`] is invoked fr
a cross-platform, self-contained bootstrap mechanism for the build.
=== Prerequisites
https://docs.github.com/en/get-started/quickstart/set-up-git[Git] and the https://www.oracle.com/java/technologies/downloads/#java17[JDK17 build].
https://help.github.com/set-up-git-redirect[Git] and the https://www.oracle.com/technetwork/java/javase/downloads[JDK11 build].
Be sure that your `JAVA_HOME` environment variable points to the `jdk-17` folder extracted from the JDK download.
Be sure that your `JAVA_HOME` environment variable points to the `jdk-11` folder extracted from the JDK download.
=== Check out sources
[indent=0]
@@ -40,38 +40,27 @@ Be sure that your `JAVA_HOME` environment variable points to the `jdk-17` folder
git clone git@github.com:spring-projects/spring-security.git
----
=== Install all `spring-*.jar` into your local Maven repository.
=== Install all spring-\* jars into your local Maven cache
[indent=0]
----
./gradlew publishToMavenLocal
----
=== Compile and test; build all JARs, distribution zips, and docs
=== Compile and test; build all jars, distribution zips, and docs
[indent=0]
----
./gradlew build
----
The reference docs are not currently included in the distribution zip.
You can build the reference docs for this branch by running the following command:
----
./gradlew :spring-security-docs:antora
----
That command publishes the docs site to the `_docs/build/site_` directory.
The https://github.com/spring-projects/spring-security/tree/docs-build[playbook branch] describes how to build the reference docs in detail.
Discover more commands with `./gradlew tasks`.
See also the https://github.com/spring-projects/spring-framework/wiki/Gradle-build-and-release-FAQ[Gradle build and release FAQ].
== Getting Support
Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow].
https://spring.io/support[Commercial support] is available too.
== Contributing
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/main/CONTRIBUTING.adoc[contributor guidelines] for details.
https://help.github.com/articles/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/main/CONTRIBUTING.adoc[contributor guidelines] for details.
== License
Spring Security is Open Source software released under the
+15 -110
View File
@@ -1,89 +1,4 @@
= Release Process
The release process for Spring Security is partially automated. The following table outlines which steps are automated and which are manual. Follow the links to read about each step.
[cols="1,1"]
|===
| Step | Status
| <<update-dependencies>>
| :x: manual
| <<check-all-issues-are-closed>>
| :white_check_mark: automated (scheduled release will abort if any issues are open)
| <<update-release-version>>
| :white_check_mark: automated
| <<update-antora-version>>
| :white_check_mark: automated
| <<build-locally>>
| :x: manual (when updating dependencies)
| <<push-release-commit>>
| :white_check_mark: automated
| <<announce-release-on-slack>>
| :white_check_mark: automated
| <<tag-release>>
| :white_check_mark: automated
| <<update-to-next-development-version>>
| :white_check_mark: automated
| <<update-version-on-project-page>>
| :x: manual
| <<update-release-notes-on-github>>
| :white_check_mark: automated
| <<close-create-milestone,Close milestone>>
| :x: manual (move issues to new milestone before release)
| <<close-create-milestone,Create milestone>>
| :white_check_mark: automated (if not already created)
| <<announce-release-on-other-channels>>
| :x: manual
|===
*When should I update dependencies manually?* Dependencies should be updated at the latest the end of the week prior to the release. This is usually the Friday following the 2nd Monday of the month (counting from the first week with a Monday). When in doubt, check the https://github.com/spring-projects/spring-security/milestones[milestones] page for release due dates.
*When do scheduled releases occur?* Automated releases are scheduled to occur at *3:15 PM UTC* on the *3rd Monday of the month* (counting from the first week with a Monday).
[NOTE]
The scheduled release process currently runs every Monday but only releases when a release is due. See the performed checks below for more information.
The automated release process occurs on the following branches:
* `main`
* `6.0.x`
* `5.8.x`
* `5.7.x`
For each of the above branches, the automated process performs the following checks before proceeding with the release:
1. _Check if the milestone is due today._ This check compares the current (SNAPSHOT) version of the branch with available milestones and chooses the first match (sorted alphabetically). If the due date on the matched milestone is *not* today, the process stops.
2. _Check if all issues are closed._ This check uses the milestone from the previous step and looks for open issues. If any open issues are found, the process stops.
[IMPORTANT]
You should ensure all issues are closed or moved to another milestone prior to a scheduled release.
If the above checks pass, the version number is updated (in `gradle.properties` and `antora.yml`) and a commit is pushed to trigger the CI process.
*How do I trigger a release manually?* You can trigger a release manually in two ways:
1. Trigger a release for a particular branch via https://github.com/spring-projects/spring-security/actions/workflows/update-scheduled-release-version.yml[`update-scheduled-release-version.yml`] on the desired branch. The above checks are performed for that branch, and the release will proceed if all checks pass. _This is the recommended way to trigger a release that did not pass the above checks during a regularly scheduled release._
2. Trigger releases for all branches via https://github.com/spring-projects/spring-security/actions/workflows/release-scheduler.yml[`release-scheduler.yml`] on the `main` branch. The above checks are performed for each branch, and only releases that pass all checks will proceed.
*When should additional manual steps be performed?* All other automated steps listed above occur during the normal CI process. Additional manual steps can be performed at any time once the builds pass and releases are finished.
*What if something goes wrong?* If the normal CI process fails, you can retry by re-running the failed jobs with the "Re-run failed jobs" option in GitHub Actions. If changes are required, you should revert the "Release x.y.z" commit, delete the tag, and proceed manually.
[#update-dependencies]
== Update dependencies
= Update Dependencies
Ensure you have no changes in your local repository.
Change to a new branch.
@@ -144,8 +59,7 @@ $ ./gradlew updateDependencies -PupdateMode=GITHUB_ISSUE -PgitHubAccessToken=<gi
Apply any fixes from your previous branch that were necessary.
[#check-all-issues-are-closed]
== Check all issues are closed
= Check All Issues are Closed
The following command will check if there are any open issues for the ticket.
Before running the command, replace the following values:
@@ -160,13 +74,11 @@ $ ./gradlew gitHubCheckMilestoneHasNoOpenIssues -PgitHubAccessToken=<github-pers
Alternatively, you can manually check using https://github.com/spring-projects/spring-security/milestones
[#update-release-version]
== Update release version
= Update Release Version
Update the version number in `gradle.properties` for the release, for example `5.5.0-M1`, `5.5.0-RC1`, `5.5.0`
[#update-antora-version]
== Update antora version
= Update Antora Version
You will need to update the antora.yml version.
If you are unsure of what the values should be, the following task will instruct you what the expected values are:
@@ -176,8 +88,7 @@ If you are unsure of what the values should be, the following task will instruct
./gradlew :spring-security-docs:antoraCheckVersion
----
[#build-locally]
== Build locally
= Build Locally
Run the build using
@@ -186,8 +97,7 @@ Run the build using
$ ./gradlew check
----
[#push-release-commit]
== Push release commit
= Push the Release Commit
Push the commit and GitHub actions will build and deploy the artifacts
If you are pushing to Maven Central, then you can get notified when its uploaded by running the following:
@@ -197,8 +107,7 @@ If you are pushing to Maven Central, then you can get notified when its uploa
$ ./scripts/release/wait-for-done.sh 5.5.0
----
[#announce-release-on-slack]
== Announce release on Slack
= Announce the release on Slack
* Announce via Slack on
https://pivotal.slack.com/messages/spring-release[#spring-release],
@@ -209,8 +118,7 @@ Something like:
spring-security-announcing 5.5.0 is available.
....
[#tag-release]
== Tag release
= Tag the release
* Tag the release and then push the tag
@@ -219,13 +127,11 @@ git tag 5.4.0-RC1
git push origin 5.4.0-RC1
....
[#update-to-next-development-version]
== Update to next development version
== 7. Update to Next Development Version
* Update `gradle.properties` version to next `+SNAPSHOT+` version, update antora.yml, and then push
[#update-version-on-project-page]
== Update version on project page
== 8. Update version on project page
The following command will update https://spring.io/projects/spring-security#learn with the new release version using the following parameters
@@ -238,8 +144,9 @@ The following command will update https://spring.io/projects/spring-security#lea
$ ./gradlew saganCreateRelease saganDeleteRelease -PgitHubAccessToken=<github-personal-access-token> -PnextVersion=<next-version> -PpreviousVersion=<previous-version>
----
[#update-release-notes-on-github]
== Update release notes on GitHub
== 9. Update Release Notes on GitHub
Generate the Release Notes replacing:
@@ -260,8 +167,7 @@ cat build/changelog/release-notes.md | xclip -selection clipboard
https://github.com/spring-projects/spring-security/releases[release on
GitHub], associate it with the tag, and paste the generated notes
[#close-create-milestone]
== Close / Create milestone
== 10. Close / Create Milestone
* In
https://github.com/spring-projects/spring-security/milestones[GitHub
@@ -270,8 +176,7 @@ Milestones], create a new milestone for the next release version
the new milestone
* Close the milestone for the release.
[#announce-release-on-other-channels]
== Announce release on other channels
== 11. Announce the release on other channels
* Create a https://spring.io/admin/blog[Blog]
* Tweet from [@SpringSecurity](https://twitter.com/springsecurity)
+2
View File
@@ -9,6 +9,8 @@ dependencies {
api 'org.springframework:spring-jdbc'
api 'org.springframework:spring-tx'
optional 'net.sf.ehcache:ehcache'
testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
@@ -49,7 +49,7 @@ import org.springframework.util.Assert;
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
.getContextHolderStrategy();
private final GrantedAuthority gaGeneralChanges;
@@ -0,0 +1,141 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import java.io.Serializable;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.springframework.security.acls.model.AclCache;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.util.FieldUtils;
import org.springframework.util.Assert;
/**
* Simple implementation of {@link AclCache} that delegates to EH-CACHE.
* <p>
* Designed to handle the transient fields in {@link AclImpl}. Note that this
* implementation assumes all {@link AclImpl} instances share the same
* {@link PermissionGrantingStrategy} and {@link AclAuthorizationStrategy} instances.
*
* @author Ben Alex
* @deprecated since 5.6. In favor of JCache based implementations
*/
@Deprecated
public class EhCacheBasedAclCache implements AclCache {
private final Ehcache cache;
private PermissionGrantingStrategy permissionGrantingStrategy;
private AclAuthorizationStrategy aclAuthorizationStrategy;
public EhCacheBasedAclCache(Ehcache cache, PermissionGrantingStrategy permissionGrantingStrategy,
AclAuthorizationStrategy aclAuthorizationStrategy) {
Assert.notNull(cache, "Cache required");
Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
this.cache = cache;
this.permissionGrantingStrategy = permissionGrantingStrategy;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
}
@Override
public void evictFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
MutableAcl acl = getFromCache(pk);
if (acl != null) {
this.cache.remove(acl.getId());
this.cache.remove(acl.getObjectIdentity());
}
}
@Override
public void evictFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
MutableAcl acl = getFromCache(objectIdentity);
if (acl != null) {
this.cache.remove(acl.getId());
this.cache.remove(acl.getObjectIdentity());
}
}
@Override
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
try {
Element element = this.cache.get(objectIdentity);
return (element != null) ? initializeTransientFields((MutableAcl) element.getValue()) : null;
}
catch (CacheException ex) {
return null;
}
}
@Override
public MutableAcl getFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
try {
Element element = this.cache.get(pk);
return (element != null) ? initializeTransientFields((MutableAcl) element.getValue()) : null;
}
catch (CacheException ex) {
return null;
}
}
@Override
public void putInCache(MutableAcl acl) {
Assert.notNull(acl, "Acl required");
Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
Assert.notNull(acl.getId(), "ID required");
if (this.aclAuthorizationStrategy == null) {
if (acl instanceof AclImpl) {
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils
.getProtectedFieldValue("aclAuthorizationStrategy", acl);
this.permissionGrantingStrategy = (PermissionGrantingStrategy) FieldUtils
.getProtectedFieldValue("permissionGrantingStrategy", acl);
}
}
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
putInCache((MutableAcl) acl.getParentAcl());
}
this.cache.put(new Element(acl.getObjectIdentity(), acl));
this.cache.put(new Element(acl.getId(), acl));
}
private MutableAcl initializeTransientFields(MutableAcl value) {
if (value instanceof AclImpl) {
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
}
if (value.getParentAcl() != null) {
initializeTransientFields((MutableAcl) value.getParentAcl());
}
return value;
}
@Override
public void clearCache() {
this.cache.removeAll();
}
}
@@ -54,7 +54,7 @@ public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
@Override
public List<Sid> getSids(Authentication authentication) {
Collection<? extends GrantedAuthority> authorities = this.roleHierarchy
.getReachableGrantedAuthorities(authentication.getAuthorities());
.getReachableGrantedAuthorities(authentication.getAuthorities());
List<Sid> sids = new ArrayList<>(authorities.size() + 1);
sids.add(new PrincipalSid(authentication));
for (GrantedAuthority authority : authorities) {
@@ -579,7 +579,7 @@ public class BasicLookupStrategy implements LookupStrategy {
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator
.createObjectIdentity(identifier, rs.getString("class"));
.createObjectIdentity(identifier, rs.getString("class"));
Acl parentAcl = null;
long parentAclId = rs.getLong("parent_object");
@@ -66,7 +66,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
private static final String DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID = "insert into acl_class (class, class_id_type) values (?, ?)";
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
.getContextHolderStrategy();
private boolean foreignKeysInDatabase = true;
@@ -37,7 +37,7 @@ public class AclFormattingUtilsTests {
assertThatIllegalArgumentException().isThrownBy(() -> AclFormattingUtils.demergePatterns(null, "SOME STRING"));
assertThatIllegalArgumentException().isThrownBy(() -> AclFormattingUtils.demergePatterns("SOME STRING", null));
assertThatIllegalArgumentException()
.isThrownBy(() -> AclFormattingUtils.demergePatterns("SOME STRING", "LONGER SOME STRING"));
.isThrownBy(() -> AclFormattingUtils.demergePatterns("SOME STRING", "LONGER SOME STRING"));
assertThatNoException().isThrownBy(() -> AclFormattingUtils.demergePatterns("SOME STRING", "SAME LENGTH"));
}
@@ -46,7 +46,7 @@ public class AclFormattingUtilsTests {
String original = "...........................A...R";
String removeBits = "...............................R";
assertThat(AclFormattingUtils.demergePatterns(original, removeBits))
.isEqualTo("...........................A....");
.isEqualTo("...........................A....");
assertThat(AclFormattingUtils.demergePatterns("ABCDEF", "......")).isEqualTo("ABCDEF");
assertThat(AclFormattingUtils.demergePatterns("ABCDEF", "GHIJKL")).isEqualTo("......");
}
@@ -56,7 +56,7 @@ public class AclFormattingUtilsTests {
assertThatIllegalArgumentException().isThrownBy(() -> AclFormattingUtils.mergePatterns(null, "SOME STRING"));
assertThatIllegalArgumentException().isThrownBy(() -> AclFormattingUtils.mergePatterns("SOME STRING", null));
assertThatIllegalArgumentException()
.isThrownBy(() -> AclFormattingUtils.mergePatterns("SOME STRING", "LONGER SOME STRING"));
.isThrownBy(() -> AclFormattingUtils.mergePatterns("SOME STRING", "LONGER SOME STRING"));
assertThatNoException().isThrownBy(() -> AclFormattingUtils.mergePatterns("SOME STRING", "SAME LENGTH"));
}
@@ -73,9 +73,9 @@ public class AclFormattingUtilsTests {
public final void testBinaryPrints() {
assertThat(AclFormattingUtils.printBinary(15)).isEqualTo("............................****");
assertThatIllegalArgumentException()
.isThrownBy(() -> AclFormattingUtils.printBinary(15, Permission.RESERVED_ON));
.isThrownBy(() -> AclFormattingUtils.printBinary(15, Permission.RESERVED_ON));
assertThatIllegalArgumentException()
.isThrownBy(() -> AclFormattingUtils.printBinary(15, Permission.RESERVED_OFF));
.isThrownBy(() -> AclFormattingUtils.printBinary(15, Permission.RESERVED_OFF));
assertThat(AclFormattingUtils.printBinary(15, 'x')).isEqualTo("............................xxxx");
}
@@ -85,7 +85,8 @@ public class AclEntryAfterInvocationCollectionFilteringProviderTests {
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(
service, Arrays.asList(mock(Permission.class)));
assertThat(provider.decide(mock(Authentication.class), new Object(),
SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null)).isNull();
SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null))
.isNull();
verify(service, never()).readAclById(any(ObjectIdentity.class), any(List.class));
}
@@ -54,7 +54,7 @@ public class AclEntryAfterInvocationProviderTests {
@Test
public void rejectsMissingPermissions() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new AclEntryAfterInvocationProvider(mock(AclService.class), null));
.isThrownBy(() -> new AclEntryAfterInvocationProvider(mock(AclService.class), null));
assertThatIllegalArgumentException().isThrownBy(
() -> new AclEntryAfterInvocationProvider(mock(AclService.class), Collections.<Permission>emptyList()));
}
@@ -112,12 +112,12 @@ public class AclEntryAfterInvocationProviderTests {
provider.setProcessDomainObjectClass(Object.class);
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
assertThatExceptionOfType(AccessDeniedException.class)
.isThrownBy(() -> provider.decide(mock(Authentication.class), new Object(),
SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object()));
.isThrownBy(() -> provider.decide(mock(Authentication.class), new Object(),
SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object()));
// Second scenario with no acls found
assertThatExceptionOfType(AccessDeniedException.class)
.isThrownBy(() -> provider.decide(mock(Authentication.class), new Object(),
SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object()));
.isThrownBy(() -> provider.decide(mock(Authentication.class), new Object(),
SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object()));
}
@Test
@@ -126,7 +126,8 @@ public class AclEntryAfterInvocationProviderTests {
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service,
Arrays.asList(mock(Permission.class)));
assertThat(provider.decide(mock(Authentication.class), new Object(),
SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null)).isNull();
SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null))
.isNull();
verify(service, never()).readAclById(any(ObjectIdentity.class), any(List.class));
}
@@ -77,14 +77,14 @@ public class AccessControlImplEntryTests {
assertThat(ace).isNotNull();
assertThat(ace).isNotEqualTo(100L);
assertThat(ace).isEqualTo(ace);
assertThat(ace).isEqualTo(
new AccessControlEntryImpl(1L, mockAcl, sid, BasePermission.ADMINISTRATION, true, true, true));
assertThat(ace)
.isEqualTo(new AccessControlEntryImpl(1L, mockAcl, sid, BasePermission.ADMINISTRATION, true, true, true));
assertThat(ace).isNotEqualTo(
new AccessControlEntryImpl(2L, mockAcl, sid, BasePermission.ADMINISTRATION, true, true, true));
assertThat(ace).isNotEqualTo(new AccessControlEntryImpl(1L, mockAcl, new PrincipalSid("scott"),
BasePermission.ADMINISTRATION, true, true, true));
assertThat(ace)
.isNotEqualTo(new AccessControlEntryImpl(1L, mockAcl, sid, BasePermission.WRITE, true, true, true));
.isNotEqualTo(new AccessControlEntryImpl(1L, mockAcl, sid, BasePermission.WRITE, true, true, true));
assertThat(ace).isNotEqualTo(
new AccessControlEntryImpl(1L, mockAcl, sid, BasePermission.ADMINISTRATION, false, true, true));
assertThat(ace).isNotEqualTo(
@@ -103,7 +103,7 @@ public class AclImplTests {
assertThatIllegalArgumentException().isThrownBy(
() -> new AclImpl(null, 1, this.authzStrategy, this.pgs, null, null, true, new PrincipalSid("joe")));
assertThatIllegalArgumentException()
.isThrownBy(() -> new AclImpl(null, 1, this.authzStrategy, this.mockAuditLogger));
.isThrownBy(() -> new AclImpl(null, 1, this.authzStrategy, this.mockAuditLogger));
}
@Test
@@ -111,7 +111,7 @@ public class AclImplTests {
assertThatIllegalArgumentException().isThrownBy(() -> new AclImpl(this.objectIdentity, null, this.authzStrategy,
this.pgs, null, null, true, new PrincipalSid("joe")));
assertThatIllegalArgumentException()
.isThrownBy(() -> new AclImpl(this.objectIdentity, null, this.authzStrategy, this.mockAuditLogger));
.isThrownBy(() -> new AclImpl(this.objectIdentity, null, this.authzStrategy, this.mockAuditLogger));
}
@Test
@@ -120,7 +120,7 @@ public class AclImplTests {
new DefaultPermissionGrantingStrategy(this.mockAuditLogger), null, null, true,
new PrincipalSid("joe")));
assertThatIllegalArgumentException()
.isThrownBy(() -> new AclImpl(this.objectIdentity, 1, null, this.mockAuditLogger));
.isThrownBy(() -> new AclImpl(this.objectIdentity, 1, null, this.mockAuditLogger));
}
@Test
@@ -128,7 +128,7 @@ public class AclImplTests {
MutableAcl acl = new AclImpl(this.objectIdentity, 1, this.authzStrategy, this.pgs, null, null, true,
new PrincipalSid("joe"));
assertThatIllegalArgumentException()
.isThrownBy(() -> acl.insertAce(0, null, new GrantedAuthoritySid("ROLE_IGNORED"), true));
.isThrownBy(() -> acl.insertAce(0, null, new GrantedAuthoritySid("ROLE_IGNORED"), true));
assertThatIllegalArgumentException().isThrownBy(() -> acl.insertAce(0, BasePermission.READ, null, true));
}
@@ -175,7 +175,7 @@ public class AclImplTests {
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
service.updateAcl(acl);
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> acl.insertAce(55, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true));
.isThrownBy(() -> acl.insertAce(55, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true));
}
@Test
@@ -223,7 +223,7 @@ public class AclImplTests {
new PrincipalSid("joe"));
Sid ben = new PrincipalSid("ben");
assertThatIllegalArgumentException()
.isThrownBy(() -> acl.isGranted(new ArrayList<>(0), Arrays.asList(ben), false));
.isThrownBy(() -> acl.isGranted(new ArrayList<>(0), Arrays.asList(ben), false));
assertThatIllegalArgumentException().isThrownBy(() -> acl.isGranted(READ, new ArrayList<>(0), false));
}
@@ -246,12 +246,14 @@ public class AclImplTests {
List<Sid> sids = Arrays.asList(new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_GUEST"));
assertThat(rootAcl.isGranted(permissions, sids, false)).isFalse();
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> rootAcl.isGranted(permissions, SCOTT, false));
.isThrownBy(() -> rootAcl.isGranted(permissions, SCOTT, false));
assertThat(rootAcl.isGranted(WRITE, SCOTT, false)).isTrue();
assertThat(rootAcl.isGranted(WRITE,
Arrays.asList(new PrincipalSid("rod"), new GrantedAuthoritySid("WRITE_ACCESS_ROLE")), false)).isFalse();
Arrays.asList(new PrincipalSid("rod"), new GrantedAuthoritySid("WRITE_ACCESS_ROLE")), false))
.isFalse();
assertThat(rootAcl.isGranted(WRITE,
Arrays.asList(new GrantedAuthoritySid("WRITE_ACCESS_ROLE"), new PrincipalSid("rod")), false)).isTrue();
Arrays.asList(new GrantedAuthoritySid("WRITE_ACCESS_ROLE"), new PrincipalSid("rod")), false))
.isTrue();
// Change the type of the Sid and check the granting process
assertThatExceptionOfType(NotFoundException.class).isThrownBy(() -> rootAcl.isGranted(WRITE,
Arrays.asList(new GrantedAuthoritySid("rod"), new PrincipalSid("WRITE_ACCESS_ROLE")), false));
@@ -292,7 +294,7 @@ public class AclImplTests {
// Check granting process for parent1
assertThat(parentAcl1.isGranted(READ, SCOTT, false)).isTrue();
assertThat(parentAcl1.isGranted(READ, Arrays.asList((Sid) new GrantedAuthoritySid("ROLE_USER_READ")), false))
.isTrue();
.isTrue();
assertThat(parentAcl1.isGranted(WRITE, BEN, false)).isTrue();
assertThat(parentAcl1.isGranted(DELETE, BEN, false)).isFalse();
assertThat(parentAcl1.isGranted(DELETE, SCOTT, false)).isFalse();
@@ -303,13 +305,13 @@ public class AclImplTests {
// Check granting process for child1
assertThat(childAcl1.isGranted(CREATE, SCOTT, false)).isTrue();
assertThat(childAcl1.isGranted(READ, Arrays.asList((Sid) new GrantedAuthoritySid("ROLE_USER_READ")), false))
.isTrue();
.isTrue();
assertThat(childAcl1.isGranted(DELETE, BEN, false)).isFalse();
// Check granting process for child2 (doesn't inherit the permissions from its
// parent)
assertThatExceptionOfType(NotFoundException.class).isThrownBy(() -> childAcl2.isGranted(CREATE, SCOTT, false));
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> childAcl2.isGranted(CREATE, Arrays.asList((Sid) new PrincipalSid("joe")), false));
.isThrownBy(() -> childAcl2.isGranted(CREATE, Arrays.asList((Sid) new PrincipalSid("joe")), false));
}
@Test
@@ -396,20 +398,20 @@ public class AclImplTests {
new PrincipalSid("joe"));
assertThat(acl.isSidLoaded(loadedSids)).isTrue();
assertThat(acl.isSidLoaded(Arrays.asList(new GrantedAuthoritySid("ROLE_IGNORED"), new PrincipalSid("ben"))))
.isTrue();
.isTrue();
assertThat(acl.isSidLoaded(Arrays.asList((Sid) new GrantedAuthoritySid("ROLE_IGNORED")))).isTrue();
assertThat(acl.isSidLoaded(BEN)).isTrue();
assertThat(acl.isSidLoaded(null)).isTrue();
assertThat(acl.isSidLoaded(new ArrayList<>(0))).isTrue();
assertThat(acl.isSidLoaded(
Arrays.asList(new GrantedAuthoritySid("ROLE_IGNORED"), new GrantedAuthoritySid("ROLE_IGNORED"))))
.isTrue();
.isTrue();
assertThat(acl.isSidLoaded(
Arrays.asList(new GrantedAuthoritySid("ROLE_GENERAL"), new GrantedAuthoritySid("ROLE_IGNORED"))))
.isFalse();
.isFalse();
assertThat(acl.isSidLoaded(
Arrays.asList(new GrantedAuthoritySid("ROLE_IGNORED"), new GrantedAuthoritySid("ROLE_GENERAL"))))
.isFalse();
.isFalse();
}
@Test
@@ -417,7 +419,7 @@ public class AclImplTests {
AclImpl acl = new AclImpl(this.objectIdentity, 1, this.authzStrategy, this.pgs, null, null, true,
new PrincipalSid("joe"));
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> acl.insertAce(-1, mock(Permission.class), mock(Sid.class), true));
.isThrownBy(() -> acl.insertAce(-1, mock(Permission.class), mock(Sid.class), true));
}
@Test
@@ -435,7 +437,7 @@ public class AclImplTests {
acl.insertAce(0, mock(Permission.class), mock(Sid.class), true);
// Size is now 1
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> acl.insertAce(2, mock(Permission.class), mock(Sid.class), true));
.isThrownBy(() -> acl.insertAce(2, mock(Permission.class), mock(Sid.class), true));
}
// SEC-1151
@@ -466,7 +468,7 @@ public class AclImplTests {
AclImpl acl = new AclImpl(this.objectIdentity, 1, this.authzStrategy, maskPgs, null, null, true,
new PrincipalSid("joe"));
Permission permission = this.permissionFactory
.buildFromMask(BasePermission.READ.getMask() | BasePermission.WRITE.getMask());
.buildFromMask(BasePermission.READ.getMask() | BasePermission.WRITE.getMask());
Sid sid = new PrincipalSid("ben");
acl.insertAce(0, permission, sid, true);
service.updateAcl(acl);
@@ -73,12 +73,12 @@ public class AclImplementationSecurityCheckTests {
new SimpleGrantedAuthority("ROLE_THREE"));
Acl acl2 = new AclImpl(identity, 1L, aclAuthorizationStrategy2, new ConsoleAuditLogger());
// Check access in case the principal has no authorization rights
assertThatExceptionOfType(NotFoundException.class).isThrownBy(
() -> aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_GENERAL));
assertThatExceptionOfType(NotFoundException.class).isThrownBy(
() -> aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_AUDITING));
assertThatExceptionOfType(NotFoundException.class).isThrownBy(
() -> aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_OWNERSHIP));
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_GENERAL));
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_AUDITING));
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_OWNERSHIP));
}
@Test
@@ -181,11 +181,11 @@ public class AclImplementationSecurityCheckTests {
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()), null, null, false,
new PrincipalSid(auth));
assertThatNoException()
.isThrownBy(() -> aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL));
assertThatExceptionOfType(NotFoundException.class).isThrownBy(
() -> aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING));
assertThatNoException().isThrownBy(
() -> aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP));
.isThrownBy(() -> aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL));
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING));
assertThatNoException()
.isThrownBy(() -> aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP));
}
}
@@ -60,7 +60,7 @@ public class ObjectIdentityImplTests {
public void testGetIdMethodConstraints() {
// Check the getId() method is present
assertThatExceptionOfType(IdentityUnavailableException.class)
.isThrownBy(() -> new ObjectIdentityImpl("A_STRING_OBJECT"));
.isThrownBy(() -> new ObjectIdentityImpl("A_STRING_OBJECT"));
// getId() should return a non-null value
MockIdDomainObject mockId = new MockIdDomainObject();
assertThatIllegalArgumentException().isThrownBy(() -> new ObjectIdentityImpl(mockId));
@@ -47,10 +47,12 @@ public class PermissionTests {
public void expectedIntegerValues() {
assertThat(BasePermission.READ.getMask()).isEqualTo(1);
assertThat(BasePermission.ADMINISTRATION.getMask()).isEqualTo(16);
assertThat(new CumulativePermission().set(BasePermission.READ).set(BasePermission.WRITE)
.set(BasePermission.CREATE).getMask()).isEqualTo(7);
assertThat(new CumulativePermission().set(BasePermission.READ)
.set(BasePermission.WRITE)
.set(BasePermission.CREATE)
.getMask()).isEqualTo(7);
assertThat(new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION).getMask())
.isEqualTo(17);
.isEqualTo(17);
}
@Test
@@ -64,20 +66,23 @@ public class PermissionTests {
this.permissionFactory.registerPublicPermissions(SpecialPermission.class);
assertThat(BasePermission.READ.toString()).isEqualTo("BasePermission[...............................R=1]");
assertThat(BasePermission.ADMINISTRATION.toString())
.isEqualTo("BasePermission[...........................A....=16]");
.isEqualTo("BasePermission[...........................A....=16]");
assertThat(new CumulativePermission().set(BasePermission.READ).toString())
.isEqualTo("CumulativePermission[...............................R=1]");
.isEqualTo("CumulativePermission[...............................R=1]");
assertThat(
new CumulativePermission().set(SpecialPermission.ENTER).set(BasePermission.ADMINISTRATION).toString())
.isEqualTo("CumulativePermission[..........................EA....=48]");
.isEqualTo("CumulativePermission[..........................EA....=48]");
assertThat(new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString())
.isEqualTo("CumulativePermission[...........................A...R=17]");
assertThat(new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
.clear(BasePermission.ADMINISTRATION).toString())
.isEqualTo("CumulativePermission[...............................R=1]");
assertThat(new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
.clear(BasePermission.ADMINISTRATION).clear(BasePermission.READ).toString())
.isEqualTo("CumulativePermission[................................=0]");
.isEqualTo("CumulativePermission[...........................A...R=17]");
assertThat(new CumulativePermission().set(BasePermission.ADMINISTRATION)
.set(BasePermission.READ)
.clear(BasePermission.ADMINISTRATION)
.toString()).isEqualTo("CumulativePermission[...............................R=1]");
assertThat(new CumulativePermission().set(BasePermission.ADMINISTRATION)
.set(BasePermission.READ)
.clear(BasePermission.ADMINISTRATION)
.clear(BasePermission.READ)
.toString()).isEqualTo("CumulativePermission[................................=0]");
}
}
@@ -16,7 +16,6 @@
package org.springframework.security.acls.jdbc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -24,15 +23,15 @@ import java.util.UUID;
import javax.sql.DataSource;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.acls.TargetObject;
import org.springframework.security.acls.TargetObjectWithUUID;
@@ -42,10 +41,10 @@ import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.ConsoleAuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.domain.SpringCacheBasedAclCache;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AuditableAccessControlEntry;
import org.springframework.security.acls.model.MutableAcl;
@@ -56,8 +55,6 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests {@link BasicLookupStrategy}
@@ -78,7 +75,7 @@ public abstract class AbstractBasicLookupStrategyTests {
private BasicLookupStrategy strategy;
private static CacheManagerMock cacheManager;
private static CacheManager cacheManager;
public abstract JdbcTemplate getJdbcTemplate();
@@ -86,13 +83,14 @@ public abstract class AbstractBasicLookupStrategyTests {
@BeforeAll
public static void initCacheManaer() {
cacheManager = new CacheManagerMock();
cacheManager.addCache("basiclookuptestcache");
cacheManager = CacheManager.create();
cacheManager.addCache(new Cache("basiclookuptestcache", 500, false, false, 30, 30));
}
@AfterAll
public static void shutdownCacheManager() {
cacheManager.clear();
cacheManager.removalAll();
cacheManager.shutdown();
}
@BeforeEach
@@ -120,17 +118,11 @@ public abstract class AbstractBasicLookupStrategyTests {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
}
protected SpringCacheBasedAclCache aclCache() {
return new SpringCacheBasedAclCache(getCache(), new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
protected EhCacheBasedAclCache aclCache() {
return new EhCacheBasedAclCache(getCache(), new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
}
protected Cache getCache() {
Cache cache = cacheManager.getCacheManager().getCache("basiclookuptestcache");
cache.clear();
return cache;
}
@AfterEach
public void emptyDatabase() {
String query = "DELETE FROM acl_entry;" + "DELETE FROM acl_object_identity WHERE ID = 9;"
@@ -142,6 +134,12 @@ public abstract class AbstractBasicLookupStrategyTests {
getJdbcTemplate().execute(query);
}
protected Ehcache getCache() {
Ehcache cache = cacheManager.getCache("basiclookuptestcache");
cache.removeAll();
return cache;
}
@Test
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, 100L);
@@ -149,7 +147,7 @@ public abstract class AbstractBasicLookupStrategyTests {
// Deliberately use an integer for the child, to reproduce bug report in SEC-819
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, 102);
Map<ObjectIdentity, Acl> map = this.strategy
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
checkEntries(topParentOid, middleParentOid, childOid, map);
}
@@ -163,7 +161,7 @@ public abstract class AbstractBasicLookupStrategyTests {
// Let's empty the database to force acls retrieval from cache
emptyDatabase();
Map<ObjectIdentity, Acl> map = this.strategy
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
checkEntries(topParentOid, middleParentOid, childOid, map);
}
@@ -176,7 +174,7 @@ public abstract class AbstractBasicLookupStrategyTests {
// acls
this.strategy.setBatchSize(1);
Map<ObjectIdentity, Acl> map = this.strategy
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
checkEntries(topParentOid, middleParentOid, childOid, map);
}
@@ -303,7 +301,7 @@ public abstract class AbstractBasicLookupStrategyTests {
getJdbcTemplate().execute(query);
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS, 104L);
assertThatIllegalArgumentException()
.isThrownBy(() -> this.strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID)));
.isThrownBy(() -> this.strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID)));
}
@Test
@@ -329,32 +327,4 @@ public abstract class AbstractBasicLookupStrategyTests {
// @formatter:on
}
private static final class CacheManagerMock {
private final List<String> cacheNames;
private final CacheManager cacheManager;
private CacheManagerMock() {
this.cacheNames = new ArrayList<>();
this.cacheManager = mock(CacheManager.class);
given(this.cacheManager.getCacheNames()).willReturn(this.cacheNames);
}
private CacheManager getCacheManager() {
return this.cacheManager;
}
private void addCache(String name) {
this.cacheNames.add(name);
Cache cache = new ConcurrentMapCache(name);
given(this.cacheManager.getCache(name)).willReturn(cache);
}
private void clear() {
this.cacheNames.clear();
}
}
}
@@ -116,7 +116,7 @@ public class BasicLookupStrategyWithAclClassTypeTests extends AbstractBasicLooku
public void testReadObjectIdentityUsingNonUuidInDatabase() {
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID, OBJECT_IDENTITY_LONG_AS_UUID);
assertThatExceptionOfType(ConversionFailedException.class)
.isThrownBy(() -> this.uuidEnabledStrategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID)));
.isThrownBy(() -> this.uuidEnabledStrategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID)));
}
}
@@ -0,0 +1,223 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.jdbc;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.List;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
import org.springframework.security.acls.domain.AclImpl;
import org.springframework.security.acls.domain.ConsoleAuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.util.FieldUtils;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Tests {@link EhCacheBasedAclCache}
*
* @author Andrei Stefan
*/
@ExtendWith(MockitoExtension.class)
public class EhCacheBasedAclCacheTests {
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
@Mock
private Ehcache cache;
@Captor
private ArgumentCaptor<Element> element;
private EhCacheBasedAclCache myCache;
private MutableAcl acl;
@BeforeEach
public void setup() {
this.myCache = new EhCacheBasedAclCache(this.cache,
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, 100L);
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
this.acl = new AclImpl(identity, 1L, aclAuthorizationStrategy, new ConsoleAuditLogger());
}
@AfterEach
public void cleanup() {
SecurityContextHolder.clearContext();
}
@Test
public void constructorRejectsNullParameters() {
assertThatIllegalArgumentException().isThrownBy(
() -> new EhCacheBasedAclCache(null, new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER"))));
}
@Test
public void methodsRejectNullParameters() {
assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.evictFromCache((Serializable) null));
assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.evictFromCache((ObjectIdentity) null));
assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.getFromCache((Serializable) null));
assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.getFromCache((ObjectIdentity) null));
assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.putInCache(null));
}
// SEC-527
@Test
public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
// Serialization test
File file = File.createTempFile("SEC_TEST", ".object");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(this.acl);
oos.close();
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
MutableAcl retrieved = (MutableAcl) ois.readObject();
ois.close();
assertThat(retrieved).isEqualTo(this.acl);
Object retrieved1 = FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", retrieved);
assertThat(retrieved1).isNull();
Object retrieved2 = FieldUtils.getProtectedFieldValue("permissionGrantingStrategy", retrieved);
assertThat(retrieved2).isNull();
}
@Test
public void clearCache() {
this.myCache.clearCache();
verify(this.cache).removeAll();
}
@Test
public void putInCache() {
this.myCache.putInCache(this.acl);
verify(this.cache, times(2)).put(this.element.capture());
assertThat(this.element.getValue().getKey()).isEqualTo(this.acl.getId());
assertThat(this.element.getValue().getObjectValue()).isEqualTo(this.acl);
assertThat(this.element.getAllValues().get(0).getKey()).isEqualTo(this.acl.getObjectIdentity());
assertThat(this.element.getAllValues().get(0).getObjectValue()).isEqualTo(this.acl);
}
@Test
public void putInCacheAclWithParent() {
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, 2L);
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl parentAcl = new AclImpl(identityParent, 2L, aclAuthorizationStrategy, new ConsoleAuditLogger());
this.acl.setParent(parentAcl);
this.myCache.putInCache(this.acl);
verify(this.cache, times(4)).put(this.element.capture());
List<Element> allValues = this.element.getAllValues();
assertThat(allValues.get(0).getKey()).isEqualTo(parentAcl.getObjectIdentity());
assertThat(allValues.get(0).getObjectValue()).isEqualTo(parentAcl);
assertThat(allValues.get(1).getKey()).isEqualTo(parentAcl.getId());
assertThat(allValues.get(1).getObjectValue()).isEqualTo(parentAcl);
assertThat(allValues.get(2).getKey()).isEqualTo(this.acl.getObjectIdentity());
assertThat(allValues.get(2).getObjectValue()).isEqualTo(this.acl);
assertThat(allValues.get(3).getKey()).isEqualTo(this.acl.getId());
assertThat(allValues.get(3).getObjectValue()).isEqualTo(this.acl);
}
@Test
public void getFromCacheSerializable() {
given(this.cache.get(this.acl.getId())).willReturn(new Element(this.acl.getId(), this.acl));
assertThat(this.myCache.getFromCache(this.acl.getId())).isEqualTo(this.acl);
}
@Test
public void getFromCacheSerializablePopulatesTransient() {
given(this.cache.get(this.acl.getId())).willReturn(new Element(this.acl.getId(), this.acl));
this.myCache.putInCache(this.acl);
ReflectionTestUtils.setField(this.acl, "permissionGrantingStrategy", null);
ReflectionTestUtils.setField(this.acl, "aclAuthorizationStrategy", null);
MutableAcl fromCache = this.myCache.getFromCache(this.acl.getId());
assertThat(ReflectionTestUtils.getField(fromCache, "aclAuthorizationStrategy")).isNotNull();
assertThat(ReflectionTestUtils.getField(fromCache, "permissionGrantingStrategy")).isNotNull();
}
@Test
public void getFromCacheObjectIdentity() {
given(this.cache.get(this.acl.getId())).willReturn(new Element(this.acl.getId(), this.acl));
assertThat(this.myCache.getFromCache(this.acl.getId())).isEqualTo(this.acl);
}
@Test
public void getFromCacheObjectIdentityPopulatesTransient() {
given(this.cache.get(this.acl.getObjectIdentity())).willReturn(new Element(this.acl.getId(), this.acl));
this.myCache.putInCache(this.acl);
ReflectionTestUtils.setField(this.acl, "permissionGrantingStrategy", null);
ReflectionTestUtils.setField(this.acl, "aclAuthorizationStrategy", null);
MutableAcl fromCache = this.myCache.getFromCache(this.acl.getObjectIdentity());
assertThat(ReflectionTestUtils.getField(fromCache, "aclAuthorizationStrategy")).isNotNull();
assertThat(ReflectionTestUtils.getField(fromCache, "permissionGrantingStrategy")).isNotNull();
}
@Test
public void evictCacheSerializable() {
given(this.cache.get(this.acl.getObjectIdentity())).willReturn(new Element(this.acl.getId(), this.acl));
this.myCache.evictFromCache(this.acl.getObjectIdentity());
verify(this.cache).remove(this.acl.getId());
verify(this.cache).remove(this.acl.getObjectIdentity());
}
@Test
public void evictCacheObjectIdentity() {
given(this.cache.get(this.acl.getId())).willReturn(new Element(this.acl.getId(), this.acl));
this.myCache.evictFromCache(this.acl.getId());
verify(this.cache).remove(this.acl.getId());
verify(this.cache).remove(this.acl.getObjectIdentity());
}
}
@@ -101,7 +101,7 @@ public class JdbcAclServiceTests {
ObjectIdentity objectIdentity = new ObjectIdentityImpl(Object.class, 1);
List<Sid> sids = Arrays.<Sid>asList(new PrincipalSid("user"));
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> this.aclService.readAclById(objectIdentity, sids));
.isThrownBy(() -> this.aclService.readAclById(objectIdentity, sids));
}
@Test
@@ -168,20 +168,20 @@ public class JdbcAclServiceTests {
assertThat(objectIdentities.size()).isEqualTo(1);
assertThat(objectIdentities.get(0).getType()).isEqualTo("costcenter");
assertThat(objectIdentities.get(0).getIdentifier())
.isEqualTo(UUID.fromString("25d93b3f-c3aa-4814-9d5e-c7c96ced7762"));
.isEqualTo(UUID.fromString("25d93b3f-c3aa-4814-9d5e-c7c96ced7762"));
}
@Test
public void setObjectIdentityGeneratorWhenNullThenThrowsIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.aclServiceIntegration.setObjectIdentityGenerator(null))
.withMessage("objectIdentityGenerator cannot be null");
.isThrownBy(() -> this.aclServiceIntegration.setObjectIdentityGenerator(null))
.withMessage("objectIdentityGenerator cannot be null");
}
@Test
public void findChildrenWhenObjectIdentityGeneratorSetThenUsed() {
this.aclServiceIntegration
.setObjectIdentityGenerator((id, type) -> new ObjectIdentityImpl(type, "prefix:" + id));
.setObjectIdentityGenerator((id, type) -> new ObjectIdentityImpl(type, "prefix:" + id));
ObjectIdentity objectIdentity = new ObjectIdentityImpl("location", "US");
this.aclServiceIntegration.setAclClassIdSupported(true);
@@ -168,7 +168,7 @@ public class JdbcMutableAclServiceTests {
this.jdbcMutableAclService.updateAcl(child);
// Let's check if we can read them back correctly
Map<ObjectIdentity, Acl> map = this.jdbcMutableAclService
.readAclsById(Arrays.asList(getTopParentOid(), getMiddleParentOid(), getChildOid()));
.readAclsById(Arrays.asList(getTopParentOid(), getMiddleParentOid(), getChildOid()));
assertThat(map).hasSize(3);
// Get the retrieved versions
MutableAcl retrievedTopParent = (MutableAcl) map.get(getTopParentOid());
@@ -196,7 +196,7 @@ public class JdbcMutableAclServiceTests {
assertThat(retrievedMiddleParent.isGranted(delete, pSid, false)).isTrue();
assertThat(retrievedChild.isGranted(delete, pSid, false)).isFalse();
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> retrievedChild.isGranted(Arrays.asList(BasePermission.ADMINISTRATION), pSid, false));
.isThrownBy(() -> retrievedChild.isGranted(Arrays.asList(BasePermission.ADMINISTRATION), pSid, false));
// Now check the inherited rights (when not explicitly overridden) also look OK
assertThat(retrievedChild.isGranted(read, pSid, false)).isTrue();
assertThat(retrievedChild.isGranted(write, pSid, false)).isFalse();
@@ -209,9 +209,9 @@ public class JdbcMutableAclServiceTests {
// Check the child permissions no longer inherit
assertThat(nonInheritingChild.isGranted(delete, pSid, true)).isFalse();
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> nonInheritingChild.isGranted(read, pSid, true));
.isThrownBy(() -> nonInheritingChild.isGranted(read, pSid, true));
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> nonInheritingChild.isGranted(write, pSid, true));
.isThrownBy(() -> nonInheritingChild.isGranted(write, pSid, true));
// Let's add an identical permission to the child, but it'll appear AFTER the
// current permission, so has no impact
nonInheritingChild.insertAce(1, BasePermission.DELETE, new PrincipalSid(this.auth), true);
@@ -266,9 +266,9 @@ public class JdbcMutableAclServiceTests {
// Delete the mid-parent and test if the child was deleted, as well
this.jdbcMutableAclService.deleteAcl(getMiddleParentOid(), true);
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> this.jdbcMutableAclService.readAclById(getMiddleParentOid()));
.isThrownBy(() -> this.jdbcMutableAclService.readAclById(getMiddleParentOid()));
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> this.jdbcMutableAclService.readAclById(getChildOid()));
.isThrownBy(() -> this.jdbcMutableAclService.readAclById(getChildOid()));
Acl acl = this.jdbcMutableAclService.readAclById(getTopParentOid());
assertThat(acl).isNotNull();
assertThat(getTopParentOid()).isEqualTo(acl.getObjectIdentity());
@@ -277,11 +277,11 @@ public class JdbcMutableAclServiceTests {
@Test
public void constructorRejectsNullParameters() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new JdbcMutableAclService(null, this.lookupStrategy, this.aclCache));
.isThrownBy(() -> new JdbcMutableAclService(null, this.lookupStrategy, this.aclCache));
assertThatIllegalArgumentException()
.isThrownBy(() -> new JdbcMutableAclService(this.dataSource, null, this.aclCache));
.isThrownBy(() -> new JdbcMutableAclService(this.dataSource, null, this.aclCache));
assertThatIllegalArgumentException()
.isThrownBy(() -> new JdbcMutableAclService(this.dataSource, this.lookupStrategy, null));
.isThrownBy(() -> new JdbcMutableAclService(this.dataSource, this.lookupStrategy, null));
}
@Test
@@ -297,7 +297,7 @@ public class JdbcMutableAclServiceTests {
this.jdbcMutableAclService.createAcl(duplicateOid);
// Try to add the same object second time
assertThatExceptionOfType(AlreadyExistsException.class)
.isThrownBy(() -> this.jdbcMutableAclService.createAcl(duplicateOid));
.isThrownBy(() -> this.jdbcMutableAclService.createAcl(duplicateOid));
}
@Test
@@ -320,7 +320,7 @@ public class JdbcMutableAclServiceTests {
try {
// checking in the class, not database
assertThatExceptionOfType(ChildrenExistException.class)
.isThrownBy(() -> this.jdbcMutableAclService.deleteAcl(getTopParentOid(), false));
.isThrownBy(() -> this.jdbcMutableAclService.deleteAcl(getTopParentOid(), false));
}
finally {
// restore to the default
@@ -392,7 +392,7 @@ public class JdbcMutableAclServiceTests {
child = (MutableAcl) this.jdbcMutableAclService.readAclById(childOid);
parent = (MutableAcl) child.getParentAcl();
assertThat(parent.getEntries()).hasSize(2)
.withFailMessage("Fails because child has a stale reference to its parent");
.withFailMessage("Fails because child has a stale reference to its parent");
assertThat(parent.getEntries().get(0).getPermission().getMask()).isEqualTo(1);
assertThat(parent.getEntries().get(0).getSid()).isEqualTo(new PrincipalSid("ben"));
assertThat(parent.getEntries().get(1).getPermission().getMask()).isEqualTo(1);
@@ -79,7 +79,7 @@ public class JdbcMutableAclServiceTestsWithAclClassId extends JdbcMutableAclServ
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID, id);
getJdbcMutableAclService().createAcl(oid);
assertThat(getJdbcMutableAclService().readAclById(new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID, id)))
.isNotNull();
.isNotNull();
}
}
@@ -46,9 +46,9 @@ public class SidTests {
// Check one Authentication-argument constructor
assertThatIllegalArgumentException().isThrownBy(() -> new PrincipalSid((Authentication) null));
assertThatIllegalArgumentException()
.isThrownBy(() -> new PrincipalSid(new TestingAuthenticationToken(null, "password")));
.isThrownBy(() -> new PrincipalSid(new TestingAuthenticationToken(null, "password")));
assertThatNoException()
.isThrownBy(() -> new PrincipalSid(new TestingAuthenticationToken("johndoe", "password")));
.isThrownBy(() -> new PrincipalSid(new TestingAuthenticationToken("johndoe", "password")));
}
@Test
@@ -60,7 +60,7 @@ public class SidTests {
// Check one GrantedAuthority-argument constructor
assertThatIllegalArgumentException().isThrownBy(() -> new GrantedAuthoritySid((GrantedAuthority) null));
assertThatIllegalArgumentException()
.isThrownBy(() -> new GrantedAuthoritySid(new SimpleGrantedAuthority(null)));
.isThrownBy(() -> new GrantedAuthoritySid(new SimpleGrantedAuthority(null)));
assertThatNoException().isThrownBy(() -> new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_TEST")));
}
@@ -100,7 +100,7 @@ public class SidTests {
assertThat(principalSid.hashCode()).isEqualTo(new PrincipalSid("johndoe").hashCode());
assertThat(principalSid.hashCode()).isNotEqualTo(new PrincipalSid("scott").hashCode());
assertThat(principalSid.hashCode())
.isNotEqualTo(new PrincipalSid(new TestingAuthenticationToken("scott", "password")).hashCode());
.isNotEqualTo(new PrincipalSid(new TestingAuthenticationToken("scott", "password")).hashCode());
}
@Test
@@ -111,7 +111,7 @@ public class SidTests {
assertThat(gaSid.hashCode()).isEqualTo(new GrantedAuthoritySid("ROLE_TEST").hashCode());
assertThat(gaSid.hashCode()).isNotEqualTo(new GrantedAuthoritySid("ROLE_TEST_2").hashCode());
assertThat(gaSid.hashCode())
.isNotEqualTo(new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_TEST_2")).hashCode());
.isNotEqualTo(new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_TEST_2")).hashCode());
}
@Test
@@ -13,10 +13,16 @@
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="aclCache" class="org.springframework.security.acls.domain.SpringCacheBasedAclCache">
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
<property name="name" value="aclCache"/>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<!-- This context is used in two tests so accept existing cache manager as the context will be reused -->
<property name="acceptExisting" value="true"/>
</bean>
</property>
<property name="cacheName" value="aclCache"/>
</bean>
</constructor-arg>
<constructor-arg>
-9
View File
@@ -1,15 +1,6 @@
apply plugin: 'io.spring.convention.spring-module'
apply plugin: 'io.freefair.aspectj'
compileAspectj {
sourceCompatibility "17"
targetCompatibility "17"
}
compileTestAspectj {
sourceCompatibility "17"
targetCompatibility "17"
}
dependencies {
management platform(project(":spring-security-dependencies"))
api "org.aspectj:aspectjrt"
@@ -101,7 +101,7 @@ public class AnnotationSecurityAspectTests {
@Test
public void securedClassMethodDeniesUnauthenticatedAccess() {
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
.isThrownBy(() -> this.secured.securedClassMethod());
.isThrownBy(() -> this.secured.securedClassMethod());
}
@Test
@@ -68,7 +68,7 @@ public class PostAuthorizeAspectTests {
@Test
public void securedClassMethodDeniesUnauthenticatedAccess() {
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
.isThrownBy(() -> this.secured.securedClassMethod());
.isThrownBy(() -> this.secured.securedClassMethod());
}
@Test
@@ -68,7 +68,7 @@ public class PreAuthorizeAspectTests {
@Test
public void securedClassMethodDeniesUnauthenticatedAccess() {
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
.isThrownBy(() -> this.secured.securedClassMethod());
.isThrownBy(() -> this.secured.securedClassMethod());
}
@Test
@@ -66,7 +66,7 @@ public class SecuredAspectTests {
@Test
public void securedClassMethodDeniesUnauthenticatedAccess() {
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
.isThrownBy(() -> this.secured.securedClassMethod());
.isThrownBy(() -> this.secured.securedClassMethod());
}
@Test
+12 -48
View File
@@ -1,15 +1,16 @@
import io.spring.gradle.IncludeRepoTask
import trang.RncToXsd
buildscript {
dependencies {
classpath "io.spring.javaformat:spring-javaformat-gradle-plugin:$springJavaformatVersion"
classpath 'io.spring.nohttp:nohttp-gradle:0.0.11'
classpath "io.freefair.gradle:aspectj-plugin:6.6-rc1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "com.netflix.nebula:nebula-project-plugin:8.2.0"
classpath libs.io.spring.javaformat.spring.javaformat.gradle.plugin
classpath libs.io.spring.nohttp.nohttp.gradle
classpath libs.io.freefair.gradle.aspectj.plugin
classpath libs.org.jetbrains.kotlin.kotlin.gradle.plugin
classpath libs.com.netflix.nebula.nebula.project.plugin
}
repositories {
maven { url 'https://plugins.gradle.org/m2/' }
gradlePluginPortal()
}
}
@@ -18,12 +19,12 @@ apply plugin: 'locks'
apply plugin: 's101'
apply plugin: 'io.spring.convention.root'
apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'org.springframework.security.update-dependencies'
apply plugin: 'org.springframework.security.update-version'
apply plugin: 'org.springframework.security.sagan'
apply plugin: 'org.springframework.github.milestone'
apply plugin: 'org.springframework.github.changelog'
apply plugin: 'org.springframework.github.release'
apply plugin: 'org.springframework.security.versions.verify-dependencies-versions'
group = 'org.springframework.security'
description = 'Spring Security'
@@ -85,46 +86,9 @@ tasks.named("dispatchGitHubWorkflow") {
}
}
tasks.named("updateDependencies") {
// we aren't Gradle 7 compatible yet
checkForGradleUpdate = false
}
updateDependenciesSettings {
gitHub {
organization = "spring-projects"
repository = "spring-security"
}
addFiles({
return [
project.file("buildSrc/src/main/groovy/io/spring/gradle/convention/CheckstylePlugin.groovy")
]
})
dependencyExcludes {
majorVersionBump()
minorVersionBump()
alphaBetaVersions()
snapshotVersions()
addRule { components ->
components.withModule("org.python:jython") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("jython updates break integration tests");
}
}
components.withModule("com.nimbusds:nimbus-jose-jwt") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("nimbus-jose-jwt gets updated when oauth2-oidc-sdk is updated to ensure consistency");
}
}
}
}
}
subprojects {
plugins.withType(JavaPlugin) {
project.sourceCompatibility=JavaVersion.VERSION_17
project.sourceCompatibility='1.8'
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
@@ -141,7 +105,7 @@ allprojects {
pluginManager.withPlugin("io.spring.convention.checkstyle", { plugin ->
configure(plugin) {
dependencies {
checkstyle "io.spring.javaformat:spring-javaformat-checkstyle:$springJavaformatVersion"
checkstyle libs.io.spring.javaformat.spring.javaformat.checkstyle
}
checkstyle {
toolVersion = '8.34'
@@ -160,7 +124,7 @@ allprojects {
tasks.withType(JavaCompile).configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(17)
languageVersion = JavaLanguageVersion.of(8)
}
}
}
@@ -174,7 +138,7 @@ if (hasProperty('buildScan')) {
nohttp {
source.exclude "buildSrc/build/**"
source.builtBy(project(':spring-security-config').tasks.withType(RncToXsd))
}
tasks.register('cloneSamples', IncludeRepoTask) {
+30 -28
View File
@@ -2,10 +2,9 @@ plugins {
id "java-gradle-plugin"
id "java"
id "groovy"
id 'com.apollographql.apollo' version '2.4.5'
}
sourceCompatibility = JavaVersion.VERSION_17
sourceCompatibility = 1.8
repositories {
gradlePluginPortal()
@@ -41,10 +40,6 @@ gradlePlugin {
id = "io.spring.convention.management-configuration"
implementationClass = "io.spring.gradle.convention.ManagementConfigurationPlugin"
}
updateDependencies {
id = "org.springframework.security.update-dependencies"
implementationClass = "org.springframework.security.convention.versions.UpdateDependenciesPlugin"
}
updateProjectVersion {
id = "org.springframework.security.update-version"
implementationClass = "org.springframework.security.convention.versions.UpdateProjectVersionPlugin"
@@ -69,6 +64,10 @@ gradlePlugin {
id = "s101"
implementationClass = "s101.S101Plugin"
}
verifyDependenciesVersions {
id = "org.springframework.security.versions.verify-dependencies-versions"
implementationClass = "org.springframework.security.convention.versions.VerifyDependenciesVersionsPlugin"
}
}
}
@@ -79,34 +78,37 @@ configurations {
}
dependencies {
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.thaiopensource:trang:20091111'
implementation 'net.sourceforge.saxon:saxon:9.1.0.8'
implementation 'org.yaml:snakeyaml:1.30'
implementation platform(libs.io.projectreactor.reactor.bom)
implementation libs.com.google.code.gson.gson
implementation libs.com.thaiopensource.trag
implementation libs.net.sourceforge.saxon.saxon
implementation libs.org.yaml.snakeyaml
implementation localGroovy()
implementation 'io.github.gradle-nexus:publish-plugin:1.1.0'
implementation 'io.projectreactor:reactor-core:3.5.7'
implementation 'org.gretty:gretty:4.0.3'
implementation 'com.apollographql.apollo:apollo-runtime:2.4.5'
implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
implementation 'com.github.spullara.mustache.java:compiler:0.9.4'
implementation 'io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.15'
implementation 'io.spring.nohttp:nohttp-gradle:0.0.11'
implementation 'net.sourceforge.htmlunit:htmlunit:2.37.0'
implementation 'org.hidetake:gradle-ssh-plugin:2.10.1'
implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.29.0'
implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'
implementation libs.io.github.gradle.nexus.publish.plugin
implementation 'io.projectreactor:reactor-core'
implementation libs.org.gretty.gretty
implementation libs.com.github.ben.manes.gradle.versions.plugin
implementation libs.com.github.spullara.mustache.java.compiler
implementation libs.io.spring.javaformat.spring.javaformat.gradle.plugin
implementation libs.io.spring.nohttp.nohttp.gradle
implementation libs.net.sourceforge.htmlunit
implementation libs.org.hidetake.gradle.ssh.plugin
implementation libs.org.jfrog.buildinfo.build.info.extractor.gradle
implementation libs.org.sonarsource.scanner.gradle.sonarqube.gradle.plugin
implementation libs.com.squareup.okhttp3.okhttp
testImplementation platform('org.junit:junit-bom:5.9.3')
testImplementation platform(libs.org.junit.junit.bom)
testImplementation platform(libs.org.mockito.mockito.bom)
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
testImplementation "org.junit.jupiter:junit-jupiter-engine"
testImplementation 'org.apache.commons:commons-io:1.3.2'
testImplementation 'org.assertj:assertj-core:3.13.2'
testImplementation 'org.mockito:mockito-core:3.12.4'
testImplementation 'org.mockito:mockito-junit-jupiter:3.12.4'
testImplementation "com.squareup.okhttp3:mockwebserver:3.14.9"
testImplementation libs.org.apache.commons.commons.io
testImplementation libs.org.assertj.assertj.core
testImplementation 'org.mockito:mockito-core'
testImplementation 'org.mockito:mockito-junit-jupiter'
testImplementation libs.com.squareup.okhttp3.mockwebserver
}
+7
View File
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files("../gradle/libs.versions.toml"))
}
}
}
@@ -54,7 +54,6 @@ public abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
pluginManager.apply("io.spring.convention.javadoc-options");
pluginManager.apply("io.spring.convention.checkstyle");
pluginManager.apply(CopyPropertiesPlugin);
pluginManager.apply("io.spring.convention.eclipse");
project.jar {
manifest.attributes["Created-By"] =
@@ -1,72 +0,0 @@
/*
* Copyright 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. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.plugins.ide.eclipse.EclipsePlugin
/**
* Plugin to tweak .classpath settings so that eclipse/sts/vscode can
* be imported cleanly.
*
* @author Janne Valkealahti
*/
class EclipsePlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.plugins.apply(EclipsePlugin)
project.eclipse {
classpath {
file {
whenMerged {
// for aspects gradle eclipse integration wrongly creates lib entries for
// aspects/build/classes/java/main and aspects/build/resources/main which
// never has anything. eclipse/sts don't care, vscode language server
// complains about missing folders. So remove those from a .classpath
entries.removeAll {
entry -> entry.kind == 'lib' && (entry.path.contains('aspects/build/classes/java/main') || entry.path.contains('aspects/build/resources/main'))
}
// there are cycles and then dependencies between projects main sources and
// test sources. Looks like gradle eclipse integration is getting confused.
// thus just relax rules so that projects always sees everything from
// dependant project.
entries
.findAll { entry -> entry instanceof org.gradle.plugins.ide.eclipse.model.ProjectDependency }
.each {
it.entryAttributes['without_test_code'] = 'false'
it.entryAttributes['test'] = 'false'
}
}
}
}
jdt {
file {
withProperties { properties ->
// there are cycles and then dependencies between projects main sources and
// test sources. Relax those from error to warning
properties['org.eclipse.jdt.core.circularClasspath'] = 'warning'
properties['org.eclipse.jdt.core.incompleteClasspath'] = 'warning'
}
}
}
}
}
}
@@ -34,7 +34,7 @@ class JacocoPlugin implements Plugin<Project> {
project.tasks.check.dependsOn project.tasks.jacocoTestReport
project.jacoco {
toolVersion = '0.8.7'
toolVersion = '0.8.2'
}
}
}
@@ -34,6 +34,14 @@ class RepositoryConventionPlugin implements Plugin<Project> {
if (forceMavenRepositories?.contains('local')) {
mavenLocal()
}
maven {
name = 'shibboleth'
url = 'https://build.shibboleth.net/nexus/content/repositories/releases/'
content {
includeGroupByRegex('org\\.opensaml.*')
includeGroupByRegex('net\\.shibboleth.*')
}
}
mavenCentral()
if (isSnapshot) {
maven {
@@ -67,12 +75,11 @@ class RepositoryConventionPlugin implements Plugin<Project> {
password project.artifactoryPassword
}
}
content {
excludeGroup('net.minidev')
}
url = 'https://repo.spring.io/release/'
}
maven {
name = 'shibboleth'
url = 'https://build.shibboleth.net/nexus/content/repositories/releases/'
}
}
}
@@ -4,6 +4,7 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.bundling.Zip
import org.springframework.gradle.xsd.CreateVersionlessXsdTask
public class SchemaZipPlugin implements Plugin<Project> {
@@ -15,7 +16,10 @@ public class SchemaZipPlugin implements Plugin<Project> {
schemaZip.archiveClassifier = 'schema'
schemaZip.description = "Builds -${schemaZip.archiveClassifier} archive containing all " +
"XSDs for deployment at static.springframework.org/schema."
def versionlessXsd = project.tasks.create("versionlessXsd", CreateVersionlessXsdTask) {
description = "Generates spring-security.xsd"
versionlessXsdFile = project.layout.buildDirectory.file("versionlessXsd/spring-security.xsd")
}
project.rootProject.subprojects.each { module ->
module.getPlugins().withType(JavaPlugin.class).all {
@@ -36,17 +40,14 @@ public class SchemaZipPlugin implements Plugin<Project> {
duplicatesStrategy 'exclude'
from xsdFile.path
}
}
File symlink = module.sourceSets.main.resources.find {
it.path.endsWith('org/springframework/security/config/spring-security.xsd')
}
if (symlink != null) {
schemaZip.into('security') {
duplicatesStrategy 'exclude'
from symlink.path
}
versionlessXsd.getInputFiles().from(xsdFile.path)
}
}
}
schemaZip.into("security") {
from(versionlessXsd.getOutputs())
}
}
}
@@ -17,14 +17,10 @@
package org.springframework.gradle.github.milestones;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -70,7 +70,7 @@ public abstract class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask {
long milestoneNumber = this.milestones.findMilestoneNumberByTitle(this.repository, this.milestoneTitle);
boolean isOpenIssues = this.milestones.isOpenIssuesForMilestoneNumber(this.repository, milestoneNumber);
Path isOpenIssuesPath = getIsOpenIssuesFile().getAsFile().get().toPath();
Files.writeString(isOpenIssuesPath, String.valueOf(isOpenIssues));
Files.write(isOpenIssuesPath, String.valueOf(isOpenIssues).getBytes());
if (isOpenIssues) {
System.out.println("The repository " + this.repository + " has open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
}
@@ -16,13 +16,10 @@
package org.springframework.gradle.github.milestones;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.tasks.TaskProvider;
import org.springframework.gradle.github.RepositoryRef;
public class GitHubMilestonePlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
@@ -19,7 +19,6 @@ package org.springframework.gradle.github.milestones;
import com.google.gson.annotations.SerializedName;
import java.time.LocalDateTime;
import java.util.Date;
/**
* @author Steve Riesenberg
@@ -16,15 +16,21 @@
package org.springframework.gradle.sagan;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.springframework.gradle.github.user.GitHubUserApi;
import org.springframework.gradle.github.user.User;
import org.springframework.util.Assert;
public class SaganCreateReleaseTask extends DefaultTask {
private static final Pattern VERSION_PATTERN = Pattern.compile("^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-.+)?$");
@Input
private String gitHubAccessToken;
@Input
@@ -44,9 +50,12 @@ public class SaganCreateReleaseTask extends DefaultTask {
// Antora reference docs URLs for snapshots do not contain -SNAPSHOT
String referenceDocUrl = this.referenceDocUrl;
if (this.version.endsWith("-SNAPSHOT")) {
referenceDocUrl = this.referenceDocUrl
.replace("{version}", this.version)
.replace("-SNAPSHOT", "");
Matcher versionMatcher = VERSION_PATTERN.matcher(this.version);
Assert.isTrue(versionMatcher.matches(), "Version " + this.version + " does not match expected pattern");
String majorVersion = versionMatcher.group(1);
String minorVersion = versionMatcher.group(2);
String majorMinorVersion = String.format("%s.%s-SNAPSHOT", majorVersion, minorVersion);
referenceDocUrl = this.referenceDocUrl.replace("{version}", majorMinorVersion);
}
SaganApi sagan = new SaganApi(user.getLogin(), this.gitHubAccessToken);
@@ -0,0 +1,147 @@
/*
* Copyright 2019-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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.xsd;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.*;
import org.gradle.work.DisableCachingByDefault;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Creates the spring-security.xsd automatically
*
* @author Rob Winch
*/
@DisableCachingByDefault(because = "not worth it")
public abstract class CreateVersionlessXsdTask extends DefaultTask {
@InputFiles
public abstract ConfigurableFileCollection getInputFiles();
@OutputFile
abstract RegularFileProperty getVersionlessXsdFile();
@TaskAction
void createVersionlessXsd() throws IOException {
XsdFileMajorMinorVersion largest = null;
ConfigurableFileCollection inputFiles = getInputFiles();
if (inputFiles.isEmpty()) {
throw new IllegalStateException("No Inputs configured");
}
for (File file : inputFiles) {
XsdFileMajorMinorVersion current = XsdFileMajorMinorVersion.create(file);
if (current == null) {
continue;
}
if (largest == null) {
largest = current;
}
else if (current.getVersion().isGreaterThan(largest.getVersion())) {
largest = current;
}
}
if (largest == null) {
throw new IllegalStateException("Could not create versionless xsd file because no files matching spring-security-<digit>.xsd were found in " + inputFiles.getFiles());
}
Path to = getVersionlessXsdFile().getAsFile().get().toPath();
Path from = largest.getFile().toPath();
Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
}
static class XsdFileMajorMinorVersion {
private final File file;
private final MajorMinorVersion version;
private XsdFileMajorMinorVersion(File file, MajorMinorVersion version) {
this.file = file;
this.version = version;
}
private static final Pattern FILE_MAJOR_MINOR_VERSION_PATTERN = Pattern.compile("^spring-security-(\\d+)\\.(\\d+)\\.xsd$");
/**
* If matches xsd with major minor version (e.g. spring-security-5.1.xsd returns it, otherwise null
* @param file
* @return
*/
static XsdFileMajorMinorVersion create(File file) {
String fileName = file.getName();
Matcher matcher = FILE_MAJOR_MINOR_VERSION_PATTERN.matcher(fileName);
if (!matcher.find()) {
return null;
}
int major = Integer.parseInt(matcher.group(1));
int minor = Integer.parseInt(matcher.group(2));
MajorMinorVersion version = new MajorMinorVersion(major, minor);
return new XsdFileMajorMinorVersion(file, version);
}
public File getFile() {
return file;
}
public MajorMinorVersion getVersion() {
return version;
}
}
static class MajorMinorVersion {
private final int major;
private final int minor;
MajorMinorVersion(int major, int minor) {
this.major = major;
this.minor = minor;
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public boolean isGreaterThan(MajorMinorVersion version) {
if (getMajor() > version.getMajor()) {
return true;
}
if (getMajor() < version.getMajor()) {
return false;
}
if (getMinor() > version.getMinor()) {
return true;
}
if (getMinor() < version.getMinor()) {
return false;
}
// they are equal
return false;
}
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.convention.versions;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Scanner;
class CommandLineUtils {
static void runCommand(File dir, String... args) {
try {
Process process = new ProcessBuilder()
.directory(dir)
.command(args)
.start();
writeLinesTo(process.getInputStream(), System.out);
writeLinesTo(process.getErrorStream(), System.out);
if (process.waitFor() != 0) {
new RuntimeException("Failed to run " + Arrays.toString(args));
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Failed to run " + Arrays.toString(args), e);
}
}
private static void writeLinesTo(InputStream input, PrintStream out) {
Scanner scanner = new Scanner(input);
while(scanner.hasNextLine()) {
out.println(scanner.nextLine());
}
}
}
@@ -1,179 +0,0 @@
package org.springframework.security.convention.versions;
import com.apollographql.apollo.ApolloCall;
import com.apollographql.apollo.ApolloClient;
import com.apollographql.apollo.api.Input;
import com.apollographql.apollo.api.Response;
import com.apollographql.apollo.exception.ApolloException;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;
import reactor.util.retry.RetrySpec;
import java.io.IOException;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class GitHubApi {
private final ApolloClient apolloClient;
public GitHubApi(String githubToken) {
if (githubToken == null) {
throw new IllegalArgumentException("githubToken is required. You can set it using -PgitHubAccessToken=");
}
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
clientBuilder.addInterceptor(new AuthorizationInterceptor(githubToken));
this.apolloClient = ApolloClient.builder()
.serverUrl("https://api.github.com/graphql")
.okHttpClient(clientBuilder.build())
.build();
}
public Mono<FindCreateIssueResult> findCreateIssueInput(String owner, String name, String milestone) {
String label = "\"type: dependency-upgrade\"";
FindCreateIssueInputQuery findCreateIssueInputQuery = new FindCreateIssueInputQuery(owner, name, Input.optional(label), Input.optional(milestone));
return Mono.create( sink -> this.apolloClient.query(findCreateIssueInputQuery)
.enqueue(new ApolloCall.Callback<FindCreateIssueInputQuery.Data>() {
@Override
public void onResponse(@NotNull Response<FindCreateIssueInputQuery.Data> response) {
if (response.hasErrors()) {
sink.error(new RuntimeException(response.getErrors().stream().map(e -> e.getMessage()).collect(Collectors.joining(" "))));
} else {
FindCreateIssueInputQuery.Data data = response.getData();
FindCreateIssueInputQuery.Repository repository = data.repository();
List<String> labels = repository.labels().nodes().stream().map(FindCreateIssueInputQuery.Node::id).collect(Collectors.toList());
if (labels.isEmpty()) {
sink.error(new IllegalArgumentException("Could not find label for " + label));
return;
}
Optional<String> firstMilestoneId = repository.milestones().nodes().stream().map(FindCreateIssueInputQuery.Node1::id).findFirst();
if (!firstMilestoneId.isPresent()) {
sink.error(new IllegalArgumentException("Could not find OPEN milestone id for " + milestone));
return;
}
String milestoneId = firstMilestoneId.get();
String repositoryId = repository.id();
String assigneeId = data.viewer().id();
sink.success(new FindCreateIssueResult(repositoryId, labels, milestoneId, assigneeId));
}
}
@Override
public void onFailure(@NotNull ApolloException e) {
sink.error(e);
}
}));
}
public static class FindCreateIssueResult {
private final String repositoryId;
private final List<String> labelIds;
private final String milestoneId;
private final String assigneeId;
public FindCreateIssueResult(String repositoryId, List<String> labelIds, String milestoneId, String assigneeId) {
this.repositoryId = repositoryId;
this.labelIds = labelIds;
this.milestoneId = milestoneId;
this.assigneeId = assigneeId;
}
public String getRepositoryId() {
return repositoryId;
}
public List<String> getLabelIds() {
return labelIds;
}
public String getMilestoneId() {
return milestoneId;
}
public String getAssigneeId() {
return assigneeId;
}
}
public Mono<RateLimitQuery.RateLimit> findRateLimit() {
return Mono.create( sink -> this.apolloClient.query(new RateLimitQuery())
.enqueue(new ApolloCall.Callback<RateLimitQuery.Data>() {
@Override
public void onResponse(@NotNull Response<RateLimitQuery.Data> response) {
if (response.hasErrors()) {
sink.error(new RuntimeException(response.getErrors().stream().map(e -> e.getMessage()).collect(Collectors.joining(" "))));
} else {
sink.success(response.getData().rateLimit());
}
}
@Override
public void onFailure(@NotNull ApolloException e) {
sink.error(e);
}
}));
}
public Mono<Integer> createIssue(String repositoryId, String title, List<String> labelIds, String milestoneId, String assigneeId) {
CreateIssueInputMutation createIssue = new CreateIssueInputMutation.Builder()
.repositoryId(repositoryId)
.title(title)
.labelIds(labelIds)
.milestoneId(milestoneId)
.assigneeId(assigneeId)
.build();
return Mono.create( sink -> this.apolloClient.mutate(createIssue)
.enqueue(new ApolloCall.Callback<CreateIssueInputMutation.Data>() {
@Override
public void onResponse(@NotNull Response<CreateIssueInputMutation.Data> response) {
if (response.hasErrors()) {
String message = response.getErrors().stream().map(e -> e.getMessage() + " " + e.getCustomAttributes() + " " + e.getLocations()).collect(Collectors.joining(" "));
if (message.contains("was submitted too quickly")) {
sink.error(new SubmittedTooQuick(message));
} else {
sink.error(new RuntimeException(message));
}
} else {
sink.success(response.getData().createIssue().issue().number());
}
}
@Override
public void onFailure(@NotNull ApolloException e) {
sink.error(e);
}
}))
.retryWhen(
RetrySpec.fixedDelay(3, Duration.ofMinutes(1))
.filter(SubmittedTooQuick.class::isInstance)
.doBeforeRetry(r -> System.out.println("Pausing for 1 minute and then retrying due to receiving \"submitted too quickly\" error from GitHub API"))
)
.cast(Integer.class);
}
public static class SubmittedTooQuick extends RuntimeException {
public SubmittedTooQuick(String message) {
super(message);
}
}
private static class AuthorizationInterceptor implements Interceptor {
private final String token;
public AuthorizationInterceptor(String token) {
this.token = token;
}
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + this.token).build();
return chain.proceed(request);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 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.
@@ -1,198 +0,0 @@
package org.springframework.security.convention.versions;
import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentSelectionRulesWithCurrent;
import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentSelectionWithCurrent;
import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ResolutionStrategyWithCurrent;
import org.gradle.api.Action;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import java.util.regex.Pattern;
public class UpdateDependenciesExtension {
private Supplier<List<File>> files;
private UpdateMode updateMode = UpdateMode.COMMIT;
private DependencyExcludes dependencyExcludes = new DependencyExcludes();
private GitHub gitHub = new GitHub();
public UpdateDependenciesExtension(Supplier<List<File>> files) {
this.files = files;
}
public void setUpdateMode(UpdateMode updateMode) {
this.updateMode = updateMode;
}
public UpdateMode getUpdateMode() {
return updateMode;
}
GitHub getGitHub() {
return this.gitHub;
}
DependencyExcludes getExcludes() {
return dependencyExcludes;
}
Supplier<List<File>> getFiles() {
return files;
}
public void setFiles(Supplier<List<File>> files) {
this.files = files;
}
public void addFiles(Supplier<List<File>> files) {
Supplier<List<File>> original = this.files;
setFiles(() -> {
List<File> result = new ArrayList<>(original.get());
result.addAll(files.get());
return result;
});
}
public void dependencyExcludes(Action<DependencyExcludes> excludes) {
excludes.execute(this.dependencyExcludes);
}
public void gitHub(Action<GitHub> gitHub) {
gitHub.execute(this.gitHub);
}
public enum UpdateMode {
COMMIT,
GITHUB_ISSUE
}
public class GitHub {
private String organization;
private String repository;
private String accessToken;
private String milestone;
public String getOrganization() {
return organization;
}
public void setOrganization(String organization) {
this.organization = organization;
}
public String getRepository() {
return repository;
}
public void setRepository(String repository) {
this.repository = repository;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getMilestone() {
return milestone;
}
public void setMilestone(String milestone) {
this.milestone = milestone;
}
}
/**
* Consider creating some Predicates instead since they are composible
*/
public class DependencyExcludes {
private List<Action<ComponentSelectionWithCurrent>> actions = new ArrayList<>();
private List<Action<ComponentSelectionRulesWithCurrent>> components = new ArrayList<>();
List<Action<ComponentSelectionWithCurrent>> getActions() {
return actions;
}
public List<Action<ComponentSelectionRulesWithCurrent>> getComponents() {
return components;
}
public DependencyExcludes alphaBetaVersions() {
this.actions.add(excludeVersionWithRegex("(?i).*?(alpha|beta).*", "an alpha or beta version"));
return this;
}
public DependencyExcludes majorVersionBump() {
this.actions.add((selection) -> {
String currentVersion = selection.getCurrentVersion();
int separator = currentVersion.indexOf(".");
String major = separator > 0 ? currentVersion.substring(0, separator) : currentVersion;
String candidateVersion = selection.getCandidate().getVersion();
Pattern calVerPattern = Pattern.compile("\\d\\d\\d\\d.*");
boolean isCalVer = calVerPattern.matcher(candidateVersion).matches();
if (!isCalVer && !candidateVersion.startsWith(major)) {
selection.reject("Cannot upgrade to new Major Version");
}
});
return this;
}
public DependencyExcludes minorVersionBump() {
this.actions.add(createExcludeMinorVersionBump());
return this;
}
public Action<ComponentSelectionWithCurrent> createExcludeMinorVersionBump() {
return (selection) -> {
String currentVersion = selection.getCurrentVersion();
int majorSeparator = currentVersion.indexOf(".");
int separator = currentVersion.indexOf(".", majorSeparator + 1);
String majorMinor = separator > 0 ? currentVersion.substring(0, separator) : currentVersion;
String candidateVersion = selection.getCandidate().getVersion();
if (!candidateVersion.startsWith(majorMinor)) {
selection.reject("Cannot upgrade to new Minor Version");
}
};
}
public DependencyExcludes releaseCandidatesVersions() {
this.actions.add(excludeVersionWithRegex("(?i).*?rc.*", "a release candidate version"));
return this;
}
public DependencyExcludes milestoneVersions() {
this.actions.add(excludeVersionWithRegex("(?i).*?m\\d+.*", "a milestone version"));
return this;
}
public DependencyExcludes snapshotVersions() {
this.actions.add(excludeVersionWithRegex(".*?-SNAPSHOT.*", "a SNAPSHOT version"));
return this;
}
public DependencyExcludes addRule(Action<ComponentSelectionRulesWithCurrent> rule) {
this.components.add(rule);
return this;
}
private Action<ComponentSelectionWithCurrent> excludeVersionWithRegex(String regex, String reason) {
Pattern pattern = Pattern.compile(regex);
return (selection) -> {
String candidateVersion = selection.getCandidate().getVersion();
if (pattern.matcher(candidateVersion).matches()) {
selection.reject(candidateVersion + " is not allowed because it is " + reason);
}
};
}
}
}
@@ -1,244 +0,0 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.convention.versions;
import com.github.benmanes.gradle.versions.reporter.result.Dependency;
import com.github.benmanes.gradle.versions.reporter.result.DependencyOutdated;
import com.github.benmanes.gradle.versions.reporter.result.Result;
import com.github.benmanes.gradle.versions.reporter.result.VersionAvailable;
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask;
import com.github.benmanes.gradle.versions.updates.gradle.GradleUpdateResult;
import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentSelectionRulesWithCurrent;
import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentSelectionWithCurrent;
import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ResolutionStrategyWithCurrent;
import groovy.lang.Closure;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
import reactor.core.publisher.Mono;
import java.io.File;
import java.time.Duration;
import java.util.*;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.springframework.security.convention.versions.TransitiveDependencyLookupUtils.NIMBUS_JOSE_JWT_NAME;
import static org.springframework.security.convention.versions.TransitiveDependencyLookupUtils.OIDC_SDK_NAME;
public class UpdateDependenciesPlugin implements Plugin<Project> {
private GitHubApi gitHubApi;
@Override
public void apply(Project project) {
UpdateDependenciesExtension updateDependenciesSettings = project.getExtensions().create("updateDependenciesSettings", UpdateDependenciesExtension.class, defaultFiles(project));
if (project.hasProperty("updateMode")) {
String updateMode = String.valueOf(project.findProperty("updateMode"));
updateDependenciesSettings.setUpdateMode(UpdateDependenciesExtension.UpdateMode.valueOf(updateMode));
}
if (project.hasProperty("nextVersion")) {
String nextVersion = String.valueOf(project.findProperty("nextVersion"));
updateDependenciesSettings.getGitHub().setMilestone(nextVersion);
}
if (project.hasProperty("gitHubAccessToken")) {
String gitHubAccessToken = String.valueOf(project.findProperty("gitHubAccessToken"));
updateDependenciesSettings.getGitHub().setAccessToken(gitHubAccessToken);
}
project.getTasks().register("updateDependencies", DependencyUpdatesTask.class, new Action<DependencyUpdatesTask>() {
@Override
public void execute(DependencyUpdatesTask updateDependencies) {
updateDependencies.setDescription("Update the dependencies");
updateDependencies.setCheckConstraints(true);
updateDependencies.setOutputFormatter(new Closure<Void>(null) {
@Override
public Void call(Object argument) {
Result result = (Result) argument;
if (gitHubApi == null && updateDependenciesSettings.getUpdateMode() != UpdateDependenciesExtension.UpdateMode.COMMIT) {
gitHubApi = new GitHubApi(updateDependenciesSettings.getGitHub().getAccessToken());
}
updateDependencies(result, project, updateDependenciesSettings);
updateGradleVersion(result, project, updateDependenciesSettings);
return null;
}
});
updateDependencies.resolutionStrategy(new Action<ResolutionStrategyWithCurrent>() {
@Override
public void execute(ResolutionStrategyWithCurrent resolution) {
resolution.componentSelection(new Action<ComponentSelectionRulesWithCurrent>() {
@Override
public void execute(ComponentSelectionRulesWithCurrent components) {
updateDependenciesSettings.getExcludes().getActions().forEach((action) -> {
components.all(action);
});
updateDependenciesSettings.getExcludes().getComponents().forEach((action) -> {
action.execute(components);
});
components.all((selection) -> {
ModuleComponentIdentifier candidate = selection.getCandidate();
if (candidate.getGroup().startsWith("org.apache.directory.") && !candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("org.apache.directory.* has breaking changes in newer versions");
}
});
String jaxbBetaRegex = ".*?b\\d+.*";
components.withModule("javax.xml.bind:jaxb-api", excludeWithRegex(jaxbBetaRegex, "Reject jaxb-api beta versions"));
components.withModule("com.sun.xml.bind:jaxb-impl", excludeWithRegex(jaxbBetaRegex, "Reject jaxb-api beta versions"));
components.withModule("commons-collections:commons-collections", excludeWithRegex("^\\d{3,}.*", "Reject commons-collections date based releases"));
}
});
}
});
}
});
}
private void updateDependencies(Result result, Project project, UpdateDependenciesExtension updateDependenciesSettings) {
SortedSet<DependencyOutdated> dependencies = result.getOutdated().getDependencies();
if (dependencies.isEmpty()) {
return;
}
Map<String, List<DependencyOutdated>> groups = new LinkedHashMap<>();
dependencies.forEach(outdated -> {
groups.computeIfAbsent(outdated.getGroup(), (key) -> new ArrayList<>()).add(outdated);
});
List<DependencyOutdated> nimbusds = groups.getOrDefault("com.nimbusds", new ArrayList<>());
DependencyOutdated oidcSdc = nimbusds.stream().filter(d -> d.getName().equals(OIDC_SDK_NAME)).findFirst().orElseGet(() -> null);
if(oidcSdc != null) {
String oidcVersion = updatedVersion(oidcSdc);
String jwtVersion = TransitiveDependencyLookupUtils.lookupJwtVersion(oidcVersion);
Dependency nimbusJoseJwtDependency = result.getCurrent().getDependencies().stream().filter(d -> d.getName().equals(NIMBUS_JOSE_JWT_NAME)).findFirst().get();
DependencyOutdated outdatedJwt = new DependencyOutdated();
outdatedJwt.setVersion(nimbusJoseJwtDependency.getVersion());
outdatedJwt.setGroup(oidcSdc.getGroup());
outdatedJwt.setName(NIMBUS_JOSE_JWT_NAME);
VersionAvailable available = new VersionAvailable();
available.setRelease(jwtVersion);
outdatedJwt.setAvailable(available);
nimbusds.add(outdatedJwt);
}
File gradlePropertiesFile = project.getRootProject().file(Project.GRADLE_PROPERTIES);
Mono<GitHubApi.FindCreateIssueResult> createIssueResult = createIssueResultMono(updateDependenciesSettings);
List<File> filesWithDependencies = updateDependenciesSettings.getFiles().get();
groups.forEach((group, outdated) -> {
outdated.forEach((dependency) -> {
String ga = dependency.getGroup() + ":" + dependency.getName() + ":";
String originalDependency = ga + dependency.getVersion();
String replacementDependency = ga + updatedVersion(dependency);
System.out.println("Update " + originalDependency + " to " + replacementDependency);
filesWithDependencies.forEach((fileWithDependency) -> {
updateDependencyInlineVersion(fileWithDependency, dependency);
updateDependencyWithVersionVariable(fileWithDependency, gradlePropertiesFile, dependency);
});
});
// commit
DependencyOutdated firstDependency = outdated.get(0);
String updatedVersion = updatedVersion(firstDependency);
String title = outdated.size() == 1 ? "Update " + firstDependency.getName() + " to " + updatedVersion : "Update " + firstDependency.getGroup() + " to " + updatedVersion;
afterGroup(updateDependenciesSettings, project.getRootDir(), title, createIssueResult);
});
}
private void afterGroup(UpdateDependenciesExtension updateDependenciesExtension, File rootDir, String title, Mono<GitHubApi.FindCreateIssueResult> createIssueResultMono) {
String commitMessage = title;
if (updateDependenciesExtension.getUpdateMode() == UpdateDependenciesExtension.UpdateMode.GITHUB_ISSUE) {
GitHubApi.FindCreateIssueResult createIssueResult = createIssueResultMono.block();
Integer issueNumber = gitHubApi.createIssue(createIssueResult.getRepositoryId(), title, createIssueResult.getLabelIds(), createIssueResult.getMilestoneId(), createIssueResult.getAssigneeId()).delayElement(Duration.ofSeconds(1)).block();
commitMessage += "\n\nCloses gh-" + issueNumber;
}
CommandLineUtils.runCommand(rootDir, "git", "commit", "-am", commitMessage);
}
private Mono<GitHubApi.FindCreateIssueResult> createIssueResultMono(UpdateDependenciesExtension updateDependenciesExtension) {
return Mono.defer(() -> {
UpdateDependenciesExtension.GitHub gitHub = updateDependenciesExtension.getGitHub();
return gitHubApi.findCreateIssueInput(gitHub.getOrganization(), gitHub.getRepository(), gitHub.getMilestone()).cache();
});
}
private void updateGradleVersion(Result result, Project project, UpdateDependenciesExtension updateDependenciesSettings) {
if (!result.getGradle().isEnabled()) {
return;
}
GradleUpdateResult current = result.getGradle().getCurrent();
GradleUpdateResult running = result.getGradle().getRunning();
if (current.compareTo(running) > 0) {
String title = "Update Gradle to " + current.getVersion();
System.out.println(title);
CommandLineUtils.runCommand(project.getRootDir(), "./gradlew", "wrapper", "--gradle-version", current.getVersion(), "--no-daemon");
afterGroup(updateDependenciesSettings, project.getRootDir(), title, createIssueResultMono(updateDependenciesSettings));
}
}
private static Supplier<List<File>> defaultFiles(Project project) {
return () -> {
List<File> result = new ArrayList<>();
result.add(project.getBuildFile());
project.getChildProjects().values().forEach((childProject) ->
result.add(childProject.getBuildFile())
);
result.add(project.getRootProject().file("buildSrc/build.gradle"));
return result;
};
}
static Action<ComponentSelectionWithCurrent> excludeWithRegex(String regex, String reason) {
Pattern pattern = Pattern.compile(regex);
return (selection) -> {
String candidateVersion = selection.getCandidate().getVersion();
if (pattern.matcher(candidateVersion).matches()) {
selection.reject(candidateVersion + " is not allowed because it is " + reason);
}
};
}
static void updateDependencyInlineVersion(File buildFile, DependencyOutdated dependency){
String ga = dependency.getGroup() + ":" + dependency.getName() + ":";
String originalDependency = ga + dependency.getVersion();
String replacementDependency = ga + updatedVersion(dependency);
FileUtils.replaceFileText(buildFile, buildFileText -> buildFileText.replace(originalDependency, replacementDependency));
}
static void updateDependencyWithVersionVariable(File scanFile, File gradlePropertiesFile, DependencyOutdated dependency) {
if (!gradlePropertiesFile.exists()) {
return;
}
FileUtils.replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> {
String ga = dependency.getGroup() + ":" + dependency.getName() + ":";
Pattern pattern = Pattern.compile("\"" + ga + "\\$\\{?([^'\"]+?)\\}?\"");
String buildFileText = FileUtils.readString(scanFile);
Matcher matcher = pattern.matcher(buildFileText);
while (matcher.find()) {
String versionVariable = matcher.group(1);
gradlePropertiesText = gradlePropertiesText.replace(versionVariable + "=" + dependency.getVersion(), versionVariable + "=" + updatedVersion(dependency));
}
return gradlePropertiesText;
});
}
private static String updatedVersion(DependencyOutdated dependency) {
VersionAvailable available = dependency.getAvailable();
String release = available.getRelease();
if (release != null) {
return release;
}
return available.getMilestone();
}
}
@@ -0,0 +1,70 @@
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.convention.versions;
import org.gradle.api.DefaultTask;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.MinimalExternalModuleDependency;
import org.gradle.api.artifacts.VersionCatalog;
import org.gradle.api.artifacts.VersionCatalogsExtension;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.TaskProvider;
public class VerifyDependenciesVersionsPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
TaskProvider<VerifyDependenciesVersionsTask> verifyDependenciesVersionsTaskProvider = project.getTasks().register("verifyDependenciesVersions", VerifyDependenciesVersionsTask.class, (task) -> {
task.setGroup("Verification");
task.setDescription("Verify that specific dependencies are using the same version");
VersionCatalog versionCatalog = project.getExtensions().getByType(VersionCatalogsExtension.class).named("libs");
MinimalExternalModuleDependency oauth2OidcSdk = versionCatalog.findLibrary("com-nimbusds-oauth2-oidc-sdk").get().get();
MinimalExternalModuleDependency nimbusJoseJwt = versionCatalog.findLibrary("com-nimbusds-nimbus-jose-jwt").get().get();
task.setOauth2OidcSdkVersion(oauth2OidcSdk.getVersionConstraint().getDisplayName());
task.setExpectedNimbusJoseJwtVersion(nimbusJoseJwt.getVersionConstraint().getDisplayName());
});
project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> checkTask.dependsOn(verifyDependenciesVersionsTaskProvider));
}
public static class VerifyDependenciesVersionsTask extends DefaultTask {
private String oauth2OidcSdkVersion;
private String expectedNimbusJoseJwtVersion;
public void setOauth2OidcSdkVersion(String oauth2OidcSdkVersion) {
this.oauth2OidcSdkVersion = oauth2OidcSdkVersion;
}
public void setExpectedNimbusJoseJwtVersion(String expectedNimbusJoseJwtVersion) {
this.expectedNimbusJoseJwtVersion = expectedNimbusJoseJwtVersion;
}
@TaskAction
public void verify() {
String transitiveNimbusJoseJwtVersion = TransitiveDependencyLookupUtils.lookupJwtVersion(this.oauth2OidcSdkVersion);
if (!transitiveNimbusJoseJwtVersion.equals(this.expectedNimbusJoseJwtVersion)) {
String message = String.format("Found transitive nimbus-jose-jwt:%s in oauth2-oidc-sdk:%s, but the project contains a different version of nimbus-jose-jwt [%s]. Please align the versions.", transitiveNimbusJoseJwtVersion, this.oauth2OidcSdkVersion, this.expectedNimbusJoseJwtVersion);
throw new IllegalStateException(message);
}
}
}
}
@@ -1 +0,0 @@
implementation-class=io.spring.gradle.convention.EclipsePlugin
@@ -5,7 +5,6 @@ import org.apache.commons.io.FileUtils;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -29,7 +28,7 @@ public class JavadocApiPluginITest {
.build();
assertThat(result.task(":api").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
File allClasses = new File(testKit.getRootDir(), "build/api/allclasses-noframe.html");
File index = new File(testKit.getRootDir(), "build/api/allclasses-index.html");
File index = new File(testKit.getRootDir(), "build/api/allclasses.html");
File listing = allClasses.exists() ? allClasses : index;
String listingText = FileUtils.readFileToString(listing);
assertThat(listingText).contains("sample/Api.html");
@@ -125,27 +125,27 @@ public class RepositoryConventionPluginTests {
private void assertSnapshotRepository(RepositoryHandler repositories) {
assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(5);
assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString())
.isEqualTo("https://repo.maven.apache.org/maven2/");
assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString())
.isEqualTo("https://repo.spring.io/snapshot/");
.isEqualTo("https://repo.maven.apache.org/maven2/");
assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
.isEqualTo("https://repo.spring.io/snapshot/");
assertThat(((MavenArtifactRepository) repositories.get(3)).getUrl().toString())
.isEqualTo("https://repo.spring.io/milestone/");
}
private void assertMilestoneRepository(RepositoryHandler repositories) {
assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(4);
assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString())
.isEqualTo("https://repo.maven.apache.org/maven2/");
assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString())
.isEqualTo("https://repo.maven.apache.org/maven2/");
assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
.isEqualTo("https://repo.spring.io/milestone/");
}
private void assertReleaseRepository(RepositoryHandler repositories) {
assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(3);
assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString())
.isEqualTo("https://repo.maven.apache.org/maven2/");
assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString())
.isEqualTo("https://repo.maven.apache.org/maven2/");
assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
.isEqualTo("https://repo.spring.io/release/");
}
@@ -3,7 +3,6 @@ package org.springframework.gradle.github.milestones;
import java.nio.charset.Charset;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.concurrent.TimeUnit;
@@ -0,0 +1,94 @@
/*
* Copyright 2019-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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.xsd;
import org.junit.jupiter.api.Test;
import org.springframework.gradle.xsd.CreateVersionlessXsdTask.MajorMinorVersion;
import org.springframework.gradle.xsd.CreateVersionlessXsdTask.XsdFileMajorMinorVersion;
import java.io.File;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
/**
* @author Rob Winch
*/
class CreateVersionlessXsdTaskTests {
@Test
void xsdCreateWhenValid() {
File file = new File("spring-security-2.0.xsd");
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
assertThat(xsdFile).isNotNull();
assertThat(xsdFile.getFile()).isEqualTo(file);
assertThat(xsdFile.getVersion().getMajor()).isEqualTo(2);
assertThat(xsdFile.getVersion().getMinor()).isEqualTo(0);
}
@Test
void xsdCreateWhenPatchReleaseThenNull() {
File file = new File("spring-security-2.0.1.xsd");
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
assertThat(xsdFile).isNull();
}
@Test
void xsdCreateWhenNotXsdFileThenNull() {
File file = new File("spring-security-2.0.txt");
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
assertThat(xsdFile).isNull();
}
@Test
void xsdCreateWhenNotStartWithSpringSecurityThenNull() {
File file = new File("spring-securityNO-2.0.xsd");
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
assertThat(xsdFile).isNull();
}
@Test
void isGreaterWhenMajorLarger() {
MajorMinorVersion larger = new MajorMinorVersion(2,0);
MajorMinorVersion smaller = new MajorMinorVersion(1,0);
assertThat(larger.isGreaterThan(smaller)).isTrue();
assertThat(smaller.isGreaterThan(larger)).isFalse();
}
@Test
void isGreaterWhenMinorLarger() {
MajorMinorVersion larger = new MajorMinorVersion(1,1);
MajorMinorVersion smaller = new MajorMinorVersion(1,0);
assertThat(larger.isGreaterThan(smaller)).isTrue();
assertThat(smaller.isGreaterThan(larger)).isFalse();
}
@Test
void isGreaterWhenMajorAndMinorLarger() {
MajorMinorVersion larger = new MajorMinorVersion(2,1);
MajorMinorVersion smaller = new MajorMinorVersion(1,0);
assertThat(larger.isGreaterThan(smaller)).isTrue();
assertThat(smaller.isGreaterThan(larger)).isFalse();
}
@Test
void isGreaterWhenSame() {
MajorMinorVersion first = new MajorMinorVersion(1,0);
MajorMinorVersion second = new MajorMinorVersion(1,0);
assertThat(first.isGreaterThan(second)).isFalse();
assertThat(second.isGreaterThan(first)).isFalse();
}
}
@@ -1,86 +0,0 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.convention.versions;
import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentSelectionWithCurrent;
import org.gradle.api.Action;
import org.gradle.api.artifacts.ComponentSelection;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.*;
public class DependencyExcludesTests {
@Test
public void createExcludeMinorVersionBumpWhenMajorVersionBumpThenReject() {
ComponentSelection componentSelection = executeCreateExcludeMinorVersionBump("1.0.0", "2.0.0");
verify(componentSelection).reject(any());
}
@Test
public void createExcludeMinorVersionBumpWhenMajorCalVersionBumpThenReject() {
ComponentSelection componentSelection = executeCreateExcludeMinorVersionBump("2000.0.0", "2001.0.0");
verify(componentSelection).reject(any());
}
@Test
public void createExcludeMinorVersionBumpWhenMinorVersionBumpThenReject() {
ComponentSelection componentSelection = executeCreateExcludeMinorVersionBump("1.0.0", "1.1.0");
verify(componentSelection).reject(any());
}
@Test
public void createExcludeMinorVersionBumpWhenMinorCalVersionBumpThenReject() {
ComponentSelection componentSelection = executeCreateExcludeMinorVersionBump("2000.0.0", "2000.1.0");
verify(componentSelection).reject(any());
}
@Test
public void createExcludeMinorVersionBumpWhenMinorAndPatchVersionBumpThenReject() {
ComponentSelection componentSelection = executeCreateExcludeMinorVersionBump("1.0.0", "1.1.1");
verify(componentSelection).reject(any());
}
@Test
public void createExcludeMinorVersionBumpWhenPatchVersionBumpThenDoesNotReject() {
ComponentSelection componentSelection = executeCreateExcludeMinorVersionBump("1.0.0", "1.0.1");
verify(componentSelection, times(0)).reject(any());
}
private ComponentSelection executeCreateExcludeMinorVersionBump(String currentVersion, String candidateVersion) {
ComponentSelection componentSelection = mock(ComponentSelection.class);
UpdateDependenciesExtension.DependencyExcludes excludes = new UpdateDependenciesExtension(() -> Collections.emptyList()).new DependencyExcludes();
Action<ComponentSelectionWithCurrent> excludeMinorVersionBump = excludes.createExcludeMinorVersionBump();
ComponentSelectionWithCurrent selection = currentVersionAndCandidateVersion(componentSelection, currentVersion, candidateVersion);
excludeMinorVersionBump.execute(selection);
return componentSelection;
}
private ComponentSelectionWithCurrent currentVersionAndCandidateVersion(ComponentSelection componentSelection, String currentVersion, String candidateVersion) {
ModuleComponentIdentifier candidate = mock(ModuleComponentIdentifier.class);
given(componentSelection.getCandidate()).willReturn(candidate);
ComponentSelectionWithCurrent selection = new ComponentSelectionWithCurrent(currentVersion, componentSelection);
given(candidate.getVersion()).willReturn(candidateVersion);
given(componentSelection.getCandidate()).willReturn(candidate);
return selection;
}
}
@@ -9,6 +9,6 @@ repositories {
}
dependencies {
optional 'jakarta.servlet:jakarta.servlet-api:5.0.0'
optional 'jakarta.servlet:jakarta.servlet-api:3.1.0'
testCompile 'junit:junit:4.12'
}
@@ -1,7 +1,7 @@
package sample;
import org.junit.Test;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
public class TheTest {
@Test
+5 -1
View File
@@ -4,13 +4,17 @@ dependencies {
management platform(project(":spring-security-dependencies"))
api project(':spring-security-core')
api project(':spring-security-web')
api 'org.apereo.cas.client:cas-client-core'
api('org.jasig.cas.client:cas-client-core') {
exclude group: 'org.glassfish.jaxb', module: 'jaxb-core'
exclude group: 'javax.xml.bind', module: 'jaxb-api'
}
api 'org.springframework:spring-beans'
api 'org.springframework:spring-context'
api 'org.springframework:spring-core'
api 'org.springframework:spring-web'
optional 'com.fasterxml.jackson.core:jackson-databind'
optional 'net.sf.ehcache:ehcache'
provided 'jakarta.servlet:jakarta.servlet-api'
@@ -18,7 +18,7 @@ package org.springframework.security.cas.authentication;
import java.util.ArrayList;
import org.apereo.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.SpringSecurityCoreVersion;
@@ -18,9 +18,9 @@ package org.springframework.security.cas.authentication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apereo.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.TicketValidationException;
import org.apereo.cas.client.validation.TicketValidator;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource;
@@ -30,7 +30,9 @@ import org.springframework.core.log.LogMessage;
import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -49,11 +51,11 @@ import org.springframework.util.Assert;
* Authentication Service (CAS).
* <p>
* This <code>AuthenticationProvider</code> is capable of validating
* {@link CasServiceTicketAuthenticationToken} requests which contain a
* {@link UsernamePasswordAuthenticationToken} requests which contain a
* <code>principal</code> name equal to either
* {@link CasServiceTicketAuthenticationToken#CAS_STATEFUL_IDENTIFIER} or
* {@link CasServiceTicketAuthenticationToken#CAS_STATELESS_IDENTIFIER}. It can also
* validate a previously created {@link CasAuthenticationToken}.
* {@link CasAuthenticationFilter#CAS_STATEFUL_IDENTIFIER} or
* {@link CasAuthenticationFilter#CAS_STATELESS_IDENTIFIER}. It can also validate a
* previously created {@link CasAuthenticationToken}.
*
* @author Ben Alex
* @author Scott Battaglia
@@ -93,6 +95,13 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
if (!supports(authentication.getClass())) {
return null;
}
if (authentication instanceof UsernamePasswordAuthenticationToken
&& (!CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER.equals(authentication.getPrincipal().toString())
&& !CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER
.equals(authentication.getPrincipal().toString()))) {
// UsernamePasswordAuthenticationToken not CAS related
return null;
}
// If an existing CasAuthenticationToken, just check we created it
if (authentication instanceof CasAuthenticationToken) {
if (this.key.hashCode() != ((CasAuthenticationToken) authentication).getKeyHash()) {
@@ -108,7 +117,8 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
"Failed to provide a CAS service ticket to validate"));
}
boolean stateless = (authentication instanceof CasServiceTicketAuthenticationToken token && token.isStateless());
boolean stateless = (authentication instanceof UsernamePasswordAuthenticationToken
&& CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER.equals(authentication.getPrincipal()));
CasAuthenticationToken result = null;
if (stateless) {
@@ -226,7 +236,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
@Override
public boolean supports(final Class<?> authentication) {
return (CasServiceTicketAuthenticationToken.class.isAssignableFrom(authentication))
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication))
|| (CasAuthenticationToken.class.isAssignableFrom(authentication))
|| (CasAssertionAuthenticationToken.class.isAssignableFrom(authentication));
}
@@ -19,7 +19,7 @@ package org.springframework.security.cas.authentication;
import java.io.Serializable;
import java.util.Collection;
import org.apereo.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
@@ -1,112 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.cas.authentication;
import java.io.Serial;
import java.util.Collection;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.Assert;
/**
* An {@link org.springframework.security.core.Authentication} implementation that is
* designed to process CAS service ticket.
*
* @author Hal Deadman
* @since 6.1
*/
public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationToken {
static final String CAS_STATELESS_IDENTIFIER = "_cas_stateless_";
static final String CAS_STATEFUL_IDENTIFIER = "_cas_stateful_";
@Serial
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final String identifier;
private Object credentials;
/**
* This constructor can be safely used by any code that wishes to create a
* <code>CasServiceTicketAuthenticationToken</code>, as the {@link #isAuthenticated()}
* will return <code>false</code>.
*
*/
public CasServiceTicketAuthenticationToken(String identifier, Object credentials) {
super(null);
this.identifier = identifier;
this.credentials = credentials;
setAuthenticated(false);
}
/**
* This constructor should only be used by <code>AuthenticationManager</code> or
* <code>AuthenticationProvider</code> implementations that are satisfied with
* producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
* authentication token.
* @param identifier
* @param credentials
* @param authorities
*/
public CasServiceTicketAuthenticationToken(String identifier, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.identifier = identifier;
this.credentials = credentials;
super.setAuthenticated(true);
}
public static CasServiceTicketAuthenticationToken stateful(Object credentials) {
return new CasServiceTicketAuthenticationToken(CAS_STATEFUL_IDENTIFIER, credentials);
}
public static CasServiceTicketAuthenticationToken stateless(Object credentials) {
return new CasServiceTicketAuthenticationToken(CAS_STATELESS_IDENTIFIER, credentials);
}
public boolean isStateless() {
return CAS_STATELESS_IDENTIFIER.equals(this.identifier);
}
@Override
public Object getCredentials() {
return this.credentials;
}
@Override
public Object getPrincipal() {
return this.identifier;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
Assert.isTrue(!isAuthenticated,
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
super.setAuthenticated(false);
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
this.credentials = null;
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.cas.authentication;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.log.LogMessage;
import org.springframework.util.Assert;
/**
* Caches tickets using a Spring IoC defined
* <a href="https://www.ehcache.org/">EHCACHE</a>.
*
* @author Ben Alex
* @deprecated since 5.6. In favor of JCache based implementations
*/
@Deprecated
public class EhCacheBasedTicketCache implements StatelessTicketCache, InitializingBean {
private static final Log logger = LogFactory.getLog(EhCacheBasedTicketCache.class);
private Ehcache cache;
@Override
public void afterPropertiesSet() {
Assert.notNull(this.cache, "cache mandatory");
}
@Override
public CasAuthenticationToken getByTicketId(final String serviceTicket) {
final Element element = this.cache.get(serviceTicket);
logger.debug(LogMessage.of(() -> "Cache hit: " + (element != null) + "; service ticket: " + serviceTicket));
return (element != null) ? (CasAuthenticationToken) element.getValue() : null;
}
public Ehcache getCache() {
return this.cache;
}
@Override
public void putTicketInCache(final CasAuthenticationToken token) {
final Element element = new Element(token.getCredentials().toString(), token);
logger.debug(LogMessage.of(() -> "Cache put: " + element.getKey()));
this.cache.put(element);
}
@Override
public void removeTicketFromCache(final CasAuthenticationToken token) {
logger.debug(LogMessage.of(() -> "Cache remove: " + token.getCredentials().toString()));
this.removeTicketFromCache(token.getCredentials().toString());
}
@Override
public void removeTicketFromCache(final String serviceTicket) {
this.cache.remove(serviceTicket);
}
public void setCache(final Ehcache cache) {
this.cache = cache;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2023 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,11 +24,11 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apereo.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AttributePrincipal;
/**
* Helps in jackson deserialization of class
* {@link org.apereo.cas.client.validation.AssertionImpl}, which is used with
* {@link org.jasig.cas.client.validation.AssertionImpl}, which is used with
* {@link org.springframework.security.cas.authentication.CasAuthenticationToken}. To use
* this class we need to register with
* {@link com.fasterxml.jackson.databind.ObjectMapper}. Type information will be stored
@@ -52,7 +52,7 @@ class AssertionImplMixin {
/**
* Mixin Constructor helps in deserialize
* {@link org.apereo.cas.client.validation.AssertionImpl}
* {@link org.jasig.cas.client.validation.AssertionImpl}
* @param principal the Principal to associate with the Assertion.
* @param validFromDate when the assertion is valid from.
* @param validUntilDate when the assertion is valid to.
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2023 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,11 +23,11 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apereo.cas.client.proxy.ProxyRetriever;
import org.jasig.cas.client.proxy.ProxyRetriever;
/**
* Helps in deserialize
* {@link org.apereo.cas.client.authentication.AttributePrincipalImpl} which is used with
* Helps in deserialize {@link org.jasig.cas.client.authentication.AttributePrincipalImpl}
* which is used with
* {@link org.springframework.security.cas.authentication.CasAuthenticationToken}. Type
* information will be stored in property named @class.
* <p>
@@ -49,7 +49,7 @@ class AttributePrincipalImplMixin {
/**
* Mixin Constructor helps in deserialize
* {@link org.apereo.cas.client.authentication.AttributePrincipalImpl}
* {@link org.jasig.cas.client.authentication.AttributePrincipalImpl}
* @param name the unique identifier for the principal.
* @param attributes the key/value pairs for this principal.
* @param proxyGrantingTicket the ticket associated with this principal.
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2023 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apereo.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2023 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,8 +18,8 @@ package org.springframework.security.cas.jackson2;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.apereo.cas.client.authentication.AttributePrincipalImpl;
import org.apereo.cas.client.validation.AssertionImpl;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.jasig.cas.client.validation.AssertionImpl;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
import org.springframework.security.jackson2.SecurityJackson2Modules;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
*/
/**
* Spring Security support for Apereo's Central Authentication Service
* (<a href="https://github.com/apereo/cas">CAS</a>).
* Spring Security support for Jasig's Central Authentication Service
* (<a href="https://www.jasig.org/cas">CAS</a>).
*/
package org.springframework.security.cas;
@@ -16,7 +16,7 @@
package org.springframework.security.cas.userdetails;
import org.apereo.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
@@ -19,7 +19,7 @@ package org.springframework.security.cas.userdetails;
import java.util.ArrayList;
import java.util.List;
import org.apereo.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,15 +18,15 @@ package org.springframework.security.cas.web;
import java.io.IOException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apereo.cas.client.util.CommonUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.util.CommonUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.util.Assert;
/**
@@ -73,8 +73,7 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
String urlEncodedService = createServiceUrl(servletRequest, response);
String redirectUrl = createRedirectUrl(urlEncodedService);
preCommence(servletRequest, response);
new DefaultRedirectStrategy().sendRedirect(servletRequest, response, redirectUrl);
// response.sendRedirect(redirectUrl);
response.sendRedirect(redirectUrl);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,20 +18,21 @@ package org.springframework.security.cas.web;
import java.io.IOException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apereo.cas.client.proxy.ProxyGrantingTicketStorage;
import org.apereo.cas.client.util.CommonUtils;
import org.apereo.cas.client.validation.TicketValidator;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.core.log.LogMessage;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource;
import org.springframework.security.core.Authentication;
@@ -41,7 +42,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -65,9 +66,9 @@ import org.springframework.util.Assert;
* <tt>filterProcessesUrl</tt>.
* <p>
* Processing the service ticket involves creating a
* <code>CasServiceTicketAuthenticationToken</code> which uses
* {@link CasServiceTicketAuthenticationToken#CAS_STATEFUL_IDENTIFIER} for the
* <code>principal</code> and the opaque ticket string as the <code>credentials</code>.
* <code>UsernamePasswordAuthenticationToken</code> which uses
* {@link #CAS_STATEFUL_IDENTIFIER} for the <code>principal</code> and the opaque ticket
* string as the <code>credentials</code>.
* <h2>Obtaining Proxy Granting Tickets</h2>
* <p>
* If specified, the filter can also monitor the <code>proxyReceptorUrl</code>. The filter
@@ -90,15 +91,15 @@ import org.springframework.util.Assert;
* {@link ServiceAuthenticationDetails#getServiceUrl()} will be used for the service url.
* <p>
* Processing the proxy ticket involves creating a
* <code>CasServiceTicketAuthenticationToken</code> which uses
* {@link CasServiceTicketAuthenticationToken#CAS_STATELESS_IDENTIFIER} for the
* <code>principal</code> and the opaque ticket string as the <code>credentials</code>.
* When a proxy ticket is successfully authenticated, the FilterChain continues and the
* <code>UsernamePasswordAuthenticationToken</code> which uses
* {@link #CAS_STATELESS_IDENTIFIER} for the <code>principal</code> and the opaque ticket
* string as the <code>credentials</code>. When a proxy ticket is successfully
* authenticated, the FilterChain continues and the
* <code>authenticationSuccessHandler</code> is not used.
* <h2>Notes about the <code>AuthenticationManager</code></h2>
* <p>
* The configured <code>AuthenticationManager</code> is expected to provide a provider
* that can recognise <code>CasServiceTicketAuthenticationToken</code>s containing this
* that can recognise <code>UsernamePasswordAuthenticationToken</code>s containing this
* special <code>principal</code> name, and process them accordingly by validation with
* the CAS server. Additionally, it should be capable of using the result of
* {@link ServiceAuthenticationDetails#getServiceUrl()} as the service when validating the
@@ -134,7 +135,7 @@ import org.springframework.util.Assert;
* NOTE: In a real application you should not use an in memory implementation. You will also want
* to ensure to clean up expired tickets by calling ProxyGrantingTicketStorage.cleanup()
* --&gt;
* &lt;b:bean id=&quot;pgtStorage&quot; class=&quot;org.apereo.cas.client.proxy.ProxyGrantingTicketStorageImpl&quot;/&gt;
* &lt;b:bean id=&quot;pgtStorage&quot; class=&quot;org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl&quot;/&gt;
* &lt;b:bean id=&quot;casAuthProvider&quot; class=&quot;org.springframework.security.cas.authentication.CasAuthenticationProvider&quot;
* p:serviceProperties-ref=&quot;serviceProperties&quot;
* p:key=&quot;casAuthProviderKey&quot;&gt;
@@ -146,7 +147,7 @@ import org.springframework.util.Assert;
* &lt;/b:property&gt;
* &lt;b:property name=&quot;ticketValidator&quot;&gt;
* &lt;b:bean
* class=&quot;org.apereo.cas.client.validation.Cas20ProxyTicketValidator&quot;
* class=&quot;org.jasig.cas.client.validation.Cas20ProxyTicketValidator&quot;
* p:acceptAnyProxy=&quot;true&quot;
* p:proxyCallbackUrl=&quot;https://service.example.com/cas-sample/login/cas/proxyreceptor&quot;
* p:proxyGrantingTicketStorage-ref=&quot;pgtStorage&quot;&gt;
@@ -177,6 +178,19 @@ import org.springframework.util.Assert;
*/
public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
/**
* Used to identify a CAS request for a stateful user agent, such as a web browser.
*/
public static final String CAS_STATEFUL_IDENTIFIER = "_cas_stateful_";
/**
* Used to identify a CAS request for a stateless user agent, such as a remoting
* protocol client (e.g. Hessian, Burlap, SOAP etc). Results in a more aggressive
* caching strategy being used, as the absence of a <code>HttpSession</code> will
* result in a new authentication attempt on every request.
*/
public static final String CAS_STATELESS_IDENTIFIER = "_cas_stateless_";
/**
* The last portion of the receptor url, i.e. /proxy/receptor
*/
@@ -193,12 +207,11 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
private AuthenticationFailureHandler proxyFailureHandler = new SimpleUrlAuthenticationFailureHandler();
private SecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
private SecurityContextRepository securityContextRepository = new NullSecurityContextRepository();
public CasAuthenticationFilter() {
super("/login/cas");
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
setSecurityContextRepository(this.securityContextRepository);
}
@Override
@@ -231,15 +244,15 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
return null;
}
String serviceTicket = obtainArtifact(request);
if (serviceTicket == null) {
this.logger.debug("Failed to obtain an artifact (cas ticket)");
serviceTicket = "";
}
boolean serviceTicketRequest = serviceTicketRequest(request, response);
CasServiceTicketAuthenticationToken authRequest = serviceTicketRequest
? CasServiceTicketAuthenticationToken.stateful(serviceTicket)
: CasServiceTicketAuthenticationToken.stateless(serviceTicket);
String username = serviceTicketRequest ? CAS_STATEFUL_IDENTIFIER : CAS_STATELESS_IDENTIFIER;
String password = obtainArtifact(request);
if (password == null) {
this.logger.debug("Failed to obtain an artifact (cas ticket)");
password = "";
}
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
password);
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
return this.getAuthenticationManager().authenticate(authRequest);
}
@@ -267,6 +280,18 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
return result;
}
/**
* Sets the {@link SecurityContextRepository} to save the {@link SecurityContext} on
* authentication success. The default action is not to save the
* {@link SecurityContext}.
* @param securityContextRepository the {@link SecurityContextRepository} to use.
* Cannot be null.
*/
public void setSecurityContextRepository(SecurityContextRepository securityContextRepository) {
Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");
this.securityContextRepository = securityContextRepository;
}
/**
* Sets the {@link AuthenticationFailureHandler} for proxy requests.
* @param proxyFailureHandler
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2023 the original author or authors.
* Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Pattern;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.util.UrlUtils;
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2023 the original author or authors.
* Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2023 the original author or authors.
* Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ package org.springframework.security.cas.web.authentication;
import java.net.MalformedURLException;
import java.util.regex.Pattern;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.cas.ServiceProperties;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,8 @@ package org.springframework.security.cas.authentication;
import java.util.ArrayList;
import java.util.List;
import org.apereo.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.AssertionImpl;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.AssertionImpl;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
@@ -19,9 +19,9 @@ package org.springframework.security.cas.authentication;
import java.util.HashMap;
import java.util.Map;
import org.apereo.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.AssertionImpl;
import org.apereo.cas.client.validation.TicketValidator;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.AssertionImpl;
import org.jasig.cas.client.validation.TicketValidator;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -29,6 +29,7 @@ import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
@@ -86,7 +87,8 @@ public class CasAuthenticationProviderTests {
cap.setServiceProperties(makeServiceProperties());
cap.setTicketValidator(new MockTicketValidator(true));
cap.afterPropertiesSet();
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateful("ST-123");
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "ST-123");
token.setDetails("details");
Authentication result = cap.authenticate(token);
// Confirm ST-123 was NOT added to the cache
@@ -118,7 +120,8 @@ public class CasAuthenticationProviderTests {
cap.setTicketValidator(new MockTicketValidator(true));
cap.setServiceProperties(makeServiceProperties());
cap.afterPropertiesSet();
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless("ST-456");
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, "ST-456");
token.setDetails("details");
Authentication result = cap.authenticate(token);
// Confirm ST-456 was added to the cache
@@ -132,7 +135,7 @@ public class CasAuthenticationProviderTests {
// Now try to authenticate again. To ensure TicketValidator not
// called again, set it to deliver an exception...
cap.setTicketValidator(new MockTicketValidator(false));
// Previously created CasServiceTicketAuthenticationToken is OK
// Previously created UsernamePasswordAuthenticationToken is OK
Authentication newResult = cap.authenticate(token);
assertThat(newResult.getPrincipal()).isEqualTo(makeUserDetailsFromAuthoritiesPopulator());
assertThat(newResult.getCredentials()).isEqualTo("ST-456");
@@ -154,7 +157,8 @@ public class CasAuthenticationProviderTests {
cap.setServiceProperties(serviceProperties);
cap.afterPropertiesSet();
String ticket = "ST-456";
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless(ticket);
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
Authentication result = cap.authenticate(token);
}
@@ -174,7 +178,8 @@ public class CasAuthenticationProviderTests {
cap.setServiceProperties(serviceProperties);
cap.afterPropertiesSet();
String ticket = "ST-456";
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless(ticket);
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
Authentication result = cap.authenticate(token);
verify(validator).validate(ticket, serviceProperties.getService());
serviceProperties.setAuthenticateAllArtifacts(true);
@@ -206,7 +211,8 @@ public class CasAuthenticationProviderTests {
cap.setTicketValidator(new MockTicketValidator(true));
cap.setServiceProperties(makeServiceProperties());
cap.afterPropertiesSet();
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateful("");
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.unauthenticated(CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "");
assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> cap.authenticate(token));
}
@@ -308,15 +314,15 @@ public class CasAuthenticationProviderTests {
cap.setTicketValidator(new MockTicketValidator(true));
cap.setServiceProperties(makeServiceProperties());
cap.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("some_normal_user",
"password", AuthorityUtils.createAuthorityList("ROLE_A"));
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
.authenticated("some_normal_user", "password", AuthorityUtils.createAuthorityList("ROLE_A"));
assertThat(cap.authenticate(token)).isNull();
}
@Test
public void supportsRequiredTokens() {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
assertThat(cap.supports(CasServiceTicketAuthenticationToken.class)).isTrue();
assertThat(cap.supports(UsernamePasswordAuthenticationToken.class)).isTrue();
assertThat(cap.supports(CasAuthenticationToken.class)).isTrue();
}
@@ -19,10 +19,11 @@ package org.springframework.security.cas.authentication;
import java.util.Collections;
import java.util.List;
import org.apereo.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.AssertionImpl;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.AssertionImpl;
import org.junit.jupiter.api.Test;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -102,7 +103,7 @@ public class CasAuthenticationTokenTests {
@Test
public void testNoArgConstructorDoesntExist() {
assertThatExceptionOfType(NoSuchMethodException.class)
.isThrownBy(() -> CasAuthenticationToken.class.getDeclaredConstructor((Class[]) null));
.isThrownBy(() -> CasAuthenticationToken.class.getDeclaredConstructor((Class[]) null));
}
@Test
@@ -115,6 +116,16 @@ public class CasAuthenticationTokenTests {
assertThat(!token1.equals(token2)).isTrue();
}
@Test
public void testNotEqualsDueToDifferentAuthenticationClass() {
final Assertion assertion = new AssertionImpl("test");
CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
makeUserDetails(), assertion);
UsernamePasswordAuthenticationToken token2 = UsernamePasswordAuthenticationToken.authenticated("Test",
"Password", this.ROLES);
assertThat(!token1.equals(token2)).isTrue();
}
@Test
public void testNotEqualsDueToKey() {
final Assertion assertion = new AssertionImpl("test");
@@ -0,0 +1,76 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.cas.authentication;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests {@link EhCacheBasedTicketCache}.
*
* @author Ben Alex
*/
public class EhCacheBasedTicketCacheTests extends AbstractStatelessTicketCacheTests {
private static CacheManager cacheManager;
@BeforeAll
public static void initCacheManaer() {
cacheManager = CacheManager.create();
cacheManager.addCache(new Cache("castickets", 500, false, false, 30, 30));
}
@AfterAll
public static void shutdownCacheManager() {
cacheManager.removalAll();
cacheManager.shutdown();
}
@Test
public void testCacheOperation() throws Exception {
EhCacheBasedTicketCache cache = new EhCacheBasedTicketCache();
cache.setCache(cacheManager.getCache("castickets"));
cache.afterPropertiesSet();
final CasAuthenticationToken token = getToken();
// Check it gets stored in the cache
cache.putTicketInCache(token);
assertThat(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ")).isEqualTo(token);
// Check it gets removed from the cache
cache.removeTicketFromCache(getToken());
assertThat(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ")).isNull();
// Check it doesn't return values for null or unknown service tickets
assertThat(cache.getByTicketId(null)).isNull();
assertThat(cache.getByTicketId("UNKNOWN_SERVICE_TICKET")).isNull();
}
@Test
public void testStartupDetectsMissingCache() throws Exception {
EhCacheBasedTicketCache cache = new EhCacheBasedTicketCache();
assertThatIllegalArgumentException().isThrownBy(cache::afterPropertiesSet);
Ehcache myCache = cacheManager.getCache("castickets");
cache.setCache(myCache);
assertThat(cache.getCache()).isEqualTo(myCache);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2023 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,9 +23,9 @@ import java.util.Date;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apereo.cas.client.authentication.AttributePrincipalImpl;
import org.apereo.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.AssertionImpl;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.AssertionImpl;
import org.json.JSONException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -79,15 +79,14 @@ public class CasAuthenticationTokenMixinTests {
+ "\"keyHash\": " + KEY.hashCode() + "," + "\"principal\": " + USER_JSON + ", " + "\"credentials\": "
+ PASSWORD + ", " + "\"authorities\": " + AUTHORITIES_ARRAYLIST_JSON + "," + "\"userDetails\": " + USER_JSON
+ "," + "\"authenticated\": true, " + "\"details\": null," + "\"assertion\": {"
+ "\"@class\": \"org.apereo.cas.client.validation.AssertionImpl\", " + "\"principal\": {"
+ "\"@class\": \"org.apereo.cas.client.authentication.AttributePrincipalImpl\", "
+ "\"@class\": \"org.jasig.cas.client.validation.AssertionImpl\", " + "\"principal\": {"
+ "\"@class\": \"org.jasig.cas.client.authentication.AttributePrincipalImpl\", "
+ "\"name\": \"assertName\", " + "\"attributes\": {\"@class\": \"java.util.Collections$EmptyMap\"}, "
+ "\"proxyGrantingTicket\": null, " + "\"proxyRetriever\": null" + "}, "
+ "\"validFromDate\": [\"java.util.Date\", " + START_DATE.getTime() + "], "
+ "\"validUntilDate\": [\"java.util.Date\", " + END_DATE.getTime() + "],"
+ "\"authenticationDate\": [\"java.util.Date\", " + START_DATE.getTime() + "], "
+ "\"attributes\": {\"@class\": \"java.util.Collections$EmptyMap\"},"
+ "\"context\": {\"@class\":\"java.util.HashMap\"}" + "}" + "}";
+ "\"attributes\": {\"@class\": \"java.util.Collections$EmptyMap\"}" + "}" + "}";
private static final String CAS_TOKEN_CLEARED_JSON = CAS_TOKEN_JSON.replaceFirst(PASSWORD, "null");
@@ -133,7 +132,7 @@ public class CasAuthenticationTokenMixinTests {
assertThat(token.getAssertion()).isNotNull().isInstanceOf(AssertionImpl.class);
assertThat(token.getKeyHash()).isEqualTo(KEY.hashCode());
assertThat(token.getUserDetails().getAuthorities()).extracting(GrantedAuthority::getAuthority)
.containsOnly("ROLE_USER");
.containsOnly("ROLE_USER");
assertThat(token.getAssertion().getAuthenticationDate()).isEqualTo(START_DATE);
assertThat(token.getAssertion().getValidFromDate()).isEqualTo(START_DATE);
assertThat(token.getAssertion().getValidUntilDate()).isEqualTo(END_DATE);
@@ -144,7 +143,7 @@ public class CasAuthenticationTokenMixinTests {
private CasAuthenticationToken createCasAuthenticationToken() {
User principal = new User("admin", "1234", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
Collection<? extends GrantedAuthority> authorities = Collections
.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
Assertion assertion = new AssertionImpl(new AttributePrincipalImpl("assertName"), START_DATE, END_DATE,
START_DATE, Collections.<String, Object>emptyMap());
return new CasAuthenticationToken(KEY, principal, principal.getPassword(), authorities,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,8 +21,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apereo.cas.client.authentication.AttributePrincipal;
import org.apereo.cas.client.validation.Assertion;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.junit.jupiter.api.Test;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
@@ -39,7 +39,7 @@ public class CasAuthenticationEntryPointTests {
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
ep.setServiceProperties(new ServiceProperties());
assertThatIllegalArgumentException().isThrownBy(ep::afterPropertiesSet)
.withMessage("loginUrl must be specified");
.withMessage("loginUrl must be specified");
}
@Test
@@ -47,7 +47,7 @@ public class CasAuthenticationEntryPointTests {
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
ep.setLoginUrl("https://cas/login");
assertThatIllegalArgumentException().isThrownBy(ep::afterPropertiesSet)
.withMessage("serviceProperties must be specified");
.withMessage("serviceProperties must be specified");
}
@Test
@@ -74,7 +74,7 @@ public class CasAuthenticationEntryPointTests {
ep.commence(request, response, null);
assertThat(
"https://cas/login?service=" + URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8"))
.isEqualTo(response.getRedirectedUrl());
.isEqualTo(response.getRedirectedUrl());
}
@Test
@@ -92,7 +92,7 @@ public class CasAuthenticationEntryPointTests {
ep.commence(request, response, null);
assertThat("https://cas/login?service="
+ URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8") + "&renew=true")
.isEqualTo(response.getRedirectedUrl());
.isEqualTo(response.getRedirectedUrl());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,13 @@
package org.springframework.security.cas.web;
import jakarta.servlet.FilterChain;
import org.apereo.cas.client.proxy.ProxyGrantingTicketStorage;
import javax.servlet.FilterChain;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
@@ -36,7 +37,6 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -45,7 +45,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
@@ -133,13 +132,14 @@ public class CasAuthenticationFilterTests {
assertThat(filter.requiresAuthentication(request, response)).isFalse();
request.setParameter(properties.getArtifactParameter(), "value");
assertThat(filter.requiresAuthentication(request, response)).isTrue();
SecurityContextHolder.getContext().setAuthentication(new AnonymousAuthenticationToken("key", "principal",
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")));
SecurityContextHolder.getContext()
.setAuthentication(new AnonymousAuthenticationToken("key", "principal",
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")));
assertThat(filter.requiresAuthentication(request, response)).isTrue();
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("un", "principal"));
assertThat(filter.requiresAuthentication(request, response)).isTrue();
SecurityContextHolder.getContext()
.setAuthentication(new TestingAuthenticationToken("un", "principal", "ROLE_ANONYMOUS"));
.setAuthentication(new TestingAuthenticationToken("un", "principal", "ROLE_ANONYMOUS"));
assertThat(filter.requiresAuthentication(request, response)).isFalse();
}
@@ -175,9 +175,9 @@ public class CasAuthenticationFilterTests {
filter.afterPropertiesSet();
filter.doFilter(request, response, chain);
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull()
.withFailMessage("Authentication should not be null");
.withFailMessage("Authentication should not be null");
verify(chain).doFilter(request, response);
verifyNoInteractions(successHandler);
verifyNoMoreInteractions(successHandler);
// validate for when the filterProcessUrl matches
filter.setFilterProcessesUrl(request.getServletPath());
SecurityContextHolder.clearContext();
@@ -186,6 +186,38 @@ public class CasAuthenticationFilterTests {
verify(successHandler).onAuthenticationSuccess(request, response, authentication);
}
@Test
public void testSecurityContextHolder() throws Exception {
SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class);
AuthenticationManager manager = mock(AuthenticationManager.class);
Authentication authentication = new TestingAuthenticationToken("un", "pwd", "ROLE_USER");
given(manager.authenticate(any(Authentication.class))).willReturn(authentication);
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setAuthenticateAllArtifacts(true);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("ticket", "ST-1-123");
request.setServletPath("/authenticate");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = mock(FilterChain.class);
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setServiceProperties(serviceProperties);
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setAuthenticationManager(manager);
filter.setSecurityContextRepository(securityContextRepository);
filter.afterPropertiesSet();
filter.doFilter(request, response, chain);
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull()
.withFailMessage("Authentication should not be null");
verify(chain).doFilter(request, response);
// validate for when the filterProcessUrl matches
filter.setFilterProcessesUrl(request.getServletPath());
SecurityContextHolder.clearContext();
filter.doFilter(request, response, chain);
ArgumentCaptor<SecurityContext> contextArg = ArgumentCaptor.forClass(SecurityContext.class);
verify(securityContextRepository).saveContext(contextArg.capture(), eq(request), eq(response));
assertThat(contextArg.getValue().getAuthentication().getPrincipal()).isEqualTo(authentication.getName());
}
// SEC-1592
@Test
public void testChainNotInvokedForProxyReceptor() throws Exception {
@@ -197,25 +229,7 @@ public class CasAuthenticationFilterTests {
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl(request.getServletPath());
filter.doFilter(request, response, chain);
verifyNoInteractions(chain);
}
@Test
public void successfulAuthenticationWhenProxyRequestThenSavesSecurityContext() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER, "ticket");
MockHttpServletResponse response = new MockHttpServletResponse();
CasAuthenticationFilter filter = new CasAuthenticationFilter();
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setAuthenticateAllArtifacts(true);
filter.setServiceProperties(serviceProperties);
SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class);
ReflectionTestUtils.setField(filter, "securityContextRepository", securityContextRepository);
filter.successfulAuthentication(request, response, new MockFilterChain(), mock(Authentication.class));
verify(securityContextRepository).saveContext(any(SecurityContext.class), eq(request), eq(response));
verifyNoMoreInteractions(chain);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2023 the original author or authors.
* Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ public class DefaultServiceAuthenticationDetailsTests {
this.request.setServerPort(8443);
this.request.setRequestURI("/cas-sample/secure/");
this.artifactPattern = DefaultServiceAuthenticationDetails
.createArtifactPattern(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
.createArtifactPattern(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
}
@AfterEach
+81 -35
View File
@@ -1,13 +1,11 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.gradle.xsd.CreateVersionlessXsdTask
import trang.RncToXsd
apply plugin: 'io.spring.convention.spring-module'
apply plugin: 'trang'
apply plugin: 'kotlin'
repositories {
maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
}
dependencies {
management platform(project(":spring-security-dependencies"))
// NB: Don't add other compile time dependencies to the config module as this breaks tooling
@@ -23,6 +21,7 @@ dependencies {
optional project(':spring-security-oauth2-client')
optional project(':spring-security-oauth2-jose')
optional project(':spring-security-oauth2-resource-server')
optional project(':spring-security-openid')
optional project(':spring-security-rsocket')
optional project(':spring-security-web')
optional 'io.projectreactor:reactor-core'
@@ -47,10 +46,9 @@ dependencies {
testImplementation project(path : ':spring-security-ldap', configuration : 'tests')
testImplementation project(path : ':spring-security-oauth2-client', configuration : 'tests')
testImplementation project(path : ':spring-security-oauth2-resource-server', configuration : 'tests')
testImplementation project(':spring-security-saml2-service-provider')
testImplementation project(path : ':spring-security-saml2-service-provider', configuration : 'tests')
testImplementation project(path : ':spring-security-saml2-service-provider', configuration : 'opensaml4MainImplementation')
testImplementation project(path : ':spring-security-web', configuration : 'tests')
testImplementation "jakarta.inject:jakarta.inject-api"
testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
@@ -62,14 +60,13 @@ dependencies {
testImplementation 'ch.qos.logback:logback-classic'
testImplementation 'io.projectreactor.netty:reactor-netty'
testImplementation 'io.rsocket:rsocket-transport-netty'
testImplementation 'jakarta.annotation:jakarta.annotation-api'
testImplementation 'jakarta.annotation:jakarta.annotation-api:1.0'
testImplementation "jakarta.inject:jakarta.inject-api"
testImplementation "jakarta.transaction:jakarta.transaction-api"
testImplementation 'jakarta.xml.bind:jakarta.xml.bind-api'
testImplementation 'jakarta.websocket:jakarta.websocket-api'
testImplementation 'jakarta.websocket:jakarta.websocket-client-api'
testImplementation 'ldapsdk:ldapsdk:4.1'
testImplementation('net.sourceforge.htmlunit:htmlunit') {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: 'xml-apis', module: 'xml-apis'
}
testImplementation "org.apache.directory.server:apacheds-core"
testImplementation "org.apache.directory.server:apacheds-core-entry"
@@ -78,14 +75,22 @@ dependencies {
testImplementation "org.apache.directory.server:apacheds-server-jndi"
testImplementation 'org.apache.directory.shared:shared-ldap'
testImplementation "com.unboundid:unboundid-ldapsdk"
testImplementation 'jakarta.persistence:jakarta.persistence-api'
testImplementation "org.hibernate.orm:hibernate-core"
testImplementation 'org.eclipse.persistence:javax.persistence'
testImplementation('org.hibernate:hibernate-entitymanager') {
exclude group: 'javax.activation', module: 'javax.activation-api'
exclude group: 'javax.persistence', module: 'javax.persistence-api'
exclude group: 'javax.xml.bind', module: 'jaxb-api'
exclude group: 'org.jboss.spec.javax.transaction', module: 'jboss-transaction-api_1.2_spec'
}
testImplementation 'org.hsqldb:hsqldb'
testImplementation 'org.mockito:mockito-core'
testImplementation "org.mockito:mockito-inline"
testImplementation ('org.openid4java:openid4java-nodeps') {
exclude group: 'com.google.code.guice', module: 'guice'
exclude group: 'commons-logging', module: 'commons-logging'
}
testImplementation('org.seleniumhq.selenium:htmlunit-driver') {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: 'xml-apis', module: 'xml-apis'
}
testImplementation('org.seleniumhq.selenium:selenium-java') {
exclude group: 'commons-logging', module: 'commons-logging'
@@ -96,43 +101,84 @@ dependencies {
testImplementation 'org.springframework:spring-jdbc'
testImplementation 'org.springframework:spring-orm'
testImplementation 'org.springframework:spring-tx'
testImplementation 'org.springframework:spring-core-test'
testImplementation ('org.springframework.data:spring-data-jpa') {
exclude group: 'org.aspectj', module: 'aspectjrt'
}
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-reactor'
testImplementation 'io.mockk:mockk'
testImplementation 'org.junit.platform:junit-platform-launcher'
testImplementation 'org.apache.maven.resolver:maven-resolver-connector-basic'
testImplementation ('org.apache.maven.resolver:maven-resolver-impl') {
exclude(group: "javax.annotation", module: "javax.annotation-api")
}
testImplementation ('org.apache.maven:maven-resolver-provider') {
exclude(group: "javax.inject", module: "javax.inject")
exclude(group: "javax.annotation", module: "javax.annotation-api")
}
testImplementation ('org.apache.maven.resolver:maven-resolver-transport-http') {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
testRuntimeOnly 'org.hsqldb:hsqldb'
}
rncToXsd {
def rncToXsd = tasks.named('rncToXsd', RncToXsd)
rncToXsd.configure {
rncDir = file('src/main/resources/org/springframework/security/config/')
xsdDir = rncDir
xslFile = new File(rncDir, 'spring-security.xsl')
}
tasks.withType(KotlinCompile).configureEach {
kotlinOptions {
languageVersion = "1.7"
apiVersion = "1.7"
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
jvmTarget = "17"
def versionlessXsd = tasks.register("versionlessXsd", CreateVersionlessXsdTask) {
inputFiles.from(rncToXsd.map { task -> project.fileTree(task.xsdDir) })
versionlessXsdFile = project.layout.buildDirectory.file("versionlessXsd/spring-security.xsd")
}
tasks.named('processResources', ProcessResources).configure {
from(versionlessXsd) {
into 'org/springframework/security/config/'
}
from(rncToXsd) {
duplicatesStrategy DuplicatesStrategy.EXCLUDE
into 'org/springframework/security/config/'
}
}
build.dependsOn rncToXsd
tasks.named('sourcesJar', Jar).configure {
from(rncToXsd) {
duplicatesStrategy DuplicatesStrategy.EXCLUDE
into 'org/springframework/security/config/'
}
}
tasks.withType(KotlinCompile).configureEach {
kotlinOptions {
languageVersion = "1.3"
apiVersion = "1.3"
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
jvmTarget = "1.8"
}
}
compileTestJava {
exclude "org/springframework/security/config/annotation/web/configurers/saml2/**", "org/springframework/security/config/http/Saml2*"
}
task compileSaml2TestJava(type: JavaCompile) {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(11)
}
source = sourceSets.test.java.srcDirs
include "org/springframework/security/config/annotation/web/configurers/saml2/**", "org/springframework/security/config/http/Saml2*"
classpath = sourceSets.test.compileClasspath
destinationDirectory = new File("${buildDir}/classes/java/test")
options.sourcepath = sourceSets.test.java.getSourceDirectories()
}
task saml2Tests(type: Test) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(11)
}
filter {
includeTestsMatching "org.springframework.security.config.annotation.web.configurers.saml2.*"
}
useJUnitPlatform()
dependsOn compileSaml2TestJava
}
test {
shouldRunAfter saml2Tests
}
tasks.named('check') {
dependsOn saml2Tests
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,15 +28,14 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -70,12 +69,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
public void defaultConfiguration() {
this.spring.register(DefaultLdapConfig.class).autowire();
LdapAuthenticationProvider provider = ldapProvider();
LdapAuthoritiesPopulator authoritiesPopulator = getAuthoritiesPopulator(provider);
assertThat(authoritiesPopulator).hasFieldOrPropertyWithValue("groupRoleAttribute", "cn");
assertThat(authoritiesPopulator).hasFieldOrPropertyWithValue("groupSearchBase", "");
assertThat(authoritiesPopulator).hasFieldOrPropertyWithValue("groupSearchFilter", "(uniqueMember={0})");
assertThat(authoritiesPopulator).extracting("searchControls").hasFieldOrPropertyWithValue("searchScope",
SearchControls.ONELEVEL_SCOPE);
assertThat(authoritiesPopulator).extracting("searchControls")
.hasFieldOrPropertyWithValue("searchScope", SearchControls.ONELEVEL_SCOPE);
assertThat(ReflectionTestUtils.getField(getAuthoritiesMapper(provider), "prefix")).isEqualTo("ROLE_");
}
@@ -85,7 +85,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
LdapAuthenticationProvider provider = ldapProvider();
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupRoleAttribute"))
.isEqualTo("group");
.isEqualTo("group");
}
@Test
@@ -94,7 +94,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
LdapAuthenticationProvider provider = ldapProvider();
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupSearchFilter"))
.isEqualTo("ou=groupName");
.isEqualTo("ou=groupName");
}
@Test
@@ -103,7 +103,8 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
LdapAuthenticationProvider provider = ldapProvider();
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "searchControls"))
.extracting("searchScope").isEqualTo(SearchControls.SUBTREE_SCOPE);
.extracting("searchScope")
.isEqualTo(SearchControls.SUBTREE_SCOPE);
}
@Test
@@ -119,8 +120,8 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
this.spring.register(BindAuthenticationConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
.andExpect(authenticated().withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
}
// SEC-2472
@@ -129,13 +130,14 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
this.spring.register(PasswordEncoderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bcrypt").password("password"))
.andExpect(authenticated().withUsername("bcrypt")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
.andExpect(authenticated().withUsername("bcrypt")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
}
private LdapAuthenticationProvider ldapProvider() {
return ((List<LdapAuthenticationProvider>) ReflectionTestUtils.getField(this.authenticationManager,
"providers")).get(0);
"providers"))
.get(0);
}
private LdapAuthoritiesPopulator getAuthoritiesPopulator(LdapAuthenticationProvider provider) {
@@ -155,12 +157,11 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
return port;
}
@Configuration
@EnableWebSecurity
static class DefaultLdapConfig extends BaseLdapProviderConfig {
@Autowired
void configure(AuthenticationManagerBuilder auth) throws Exception {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
@@ -169,20 +170,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
// @formatter:on
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
@Configuration
@EnableWebSecurity
static class GroupRolesConfig extends BaseLdapProviderConfig {
@Autowired
void configure(AuthenticationManagerBuilder auth) throws Exception {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
@@ -192,20 +186,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
// @formatter:on
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
@Configuration
@EnableWebSecurity
static class GroupSearchConfig extends BaseLdapProviderConfig {
@Autowired
void configure(AuthenticationManagerBuilder auth) throws Exception {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
@@ -215,20 +202,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
// @formatter:on
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
@Configuration
@EnableWebSecurity
static class GroupSubtreeSearchConfig extends BaseLdapProviderConfig {
@Autowired
void configure(AuthenticationManagerBuilder auth) throws Exception {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
@@ -239,20 +219,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
// @formatter:on
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
@Configuration
@EnableWebSecurity
static class RolePrefixConfig extends BaseLdapProviderConfig {
@Autowired
void configure(AuthenticationManagerBuilder auth) throws Exception {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
@@ -262,20 +235,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
// @formatter:on
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
@Configuration
@EnableWebSecurity
static class BindAuthenticationConfig extends BaseLdapServerConfig {
@Autowired
void configure(AuthenticationManagerBuilder auth) throws Exception {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
@@ -286,20 +252,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
// @formatter:on
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
@Configuration
@EnableWebSecurity
static class PasswordEncoderConfig extends BaseLdapServerConfig {
@Autowired
void configure(AuthenticationManagerBuilder auth) throws Exception {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
@@ -311,15 +270,8 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
// @formatter:on
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
@Configuration
@EnableWebSecurity
abstract static class BaseLdapServerConfig extends BaseLdapProviderConfig {
@@ -333,11 +285,10 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
}
@Configuration
@EnableWebSecurity
@EnableGlobalAuthentication
@Import(ObjectPostProcessorConfiguration.class)
abstract static class BaseLdapProviderConfig {
abstract static class BaseLdapProviderConfig extends WebSecurityConfigurerAdapter {
@Bean
BaseLdapPathContextSource contextSource() throws Exception {
@@ -349,6 +300,15 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
return contextSource;
}
@Bean
AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) throws Exception {
configure(auth);
return auth.build();
}
@Override
protected abstract void configure(AuthenticationManagerBuilder auth) throws Exception;
}
}

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