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

Compare commits

...

133 Commits

Author SHA1 Message Date
github-actions[bot] 30056be789 Release 6.4.7 2025-06-16 15:08:24 +00:00
Rob Winch b8c19f9df5 Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final 2025-06-16 09:45:36 -05:00
Rob Winch 17fe96e4a7 Merge branch '6.3.x' into 6.4.x 2025-06-16 09:05:57 -05:00
Rob Winch 0a15dcaadf Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 2025-06-16 08:56:08 -05:00
Rob Winch 1fcba70c61 Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 2025-06-16 08:56:06 -05:00
Rob Winch 03a11d6ffd Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 2025-06-16 08:56:04 -05:00
Rob Winch 49cddee343 Bump org.springframework:spring-framework-bom from 6.1.20 to 6.1.21 2025-06-16 08:55:32 -05:00
Rob Winch 1c56c0c0c8 Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 2025-06-16 08:55:30 -05:00
Rob Winch d79cf75dfb Bump org.springframework.data:spring-data-bom from 2024.0.12 to 2024.0.13 2025-06-16 08:55:28 -05:00
dependabot[bot] e34c5e73e1 Bump org.springframework.data:spring-data-bom
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.12 to 2024.0.13.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.12...2024.0.13)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 04:01:56 +00:00
dependabot[bot] 29866df7cf Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 03:52:20 +00:00
dependabot[bot] aca7c4f5c4 Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final
Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final.
- [Release notes](https://github.com/hibernate/hibernate-orm/releases)
- [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt)
- [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18)

---
updated-dependencies:
- dependency-name: org.hibernate.orm:hibernate-core
  dependency-version: 6.6.18.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 03:52:13 +00:00
dependabot[bot] 46254e01fb Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13
Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13.
- [Release notes](https://github.com/spring-projects/spring-ldap/releases)
- [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt)
- [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13)

---
updated-dependencies:
- dependency-name: org.springframework.ldap:spring-ldap-core
  dependency-version: 3.2.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 03:36:23 +00:00
dependabot[bot] effe682fc4 Bump org.springframework:spring-framework-bom from 6.1.20 to 6.1.21
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.20 to 6.1.21.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.20...v6.1.21)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 03:35:50 +00:00
dependabot[bot] 9f487ad0bc Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13
Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13.
- [Release notes](https://github.com/spring-projects/spring-ldap/releases)
- [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt)
- [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13)

---
updated-dependencies:
- dependency-name: org.springframework.ldap:spring-ldap-core
  dependency-version: 3.2.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 03:11:55 +00:00
dependabot[bot] c1492f0e4e Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 03:11:19 +00:00
Rob Winch df90cd5e23 Merge branch '6.3.x' into 6.4.x 2025-06-12 12:26:21 -05:00
Rob Winch d32b6629b7 Merge branch 'gradle/6.4.x/io.projectreactor-reactor-bom-2023.0.19' into 6.4.x 2025-06-12 12:24:21 -05:00
dependabot[bot] 7f36155b47 Bump io.projectreactor:reactor-bom from 2023.0.18 to 2023.0.19
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.18 to 2023.0.19.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2023.0.18...2023.0.19)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-11 03:59:26 +00:00
dependabot[bot] 53ce08d79d Bump io.projectreactor:reactor-bom from 2023.0.18 to 2023.0.19
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.18 to 2023.0.19.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2023.0.18...2023.0.19)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-11 03:36:18 +00:00
dependabot[bot] cc40879f05 Bump com.fasterxml.jackson:jackson-bom from 2.18.4 to 2.18.4.1
Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.18.4 to 2.18.4.1.
- [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.4...jackson-bom-2.18.4.1)

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson:jackson-bom
  dependency-version: 2.18.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-11 03:35:43 +00:00
Rob Winch 29ec4c8736 Merge branch '6.3.x' into 6.4.x 2025-06-10 10:48:44 -05:00
Rob Winch 888d87619d Explicit Permissions for codeql.yml 2025-06-10 10:48:37 -05:00
dependabot[bot] d7bada7fec Bump io.micrometer:micrometer-observation from 1.14.7 to 1.14.8
Bumps [io.micrometer:micrometer-observation](https://github.com/micrometer-metrics/micrometer) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/micrometer-metrics/micrometer/releases)
- [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: io.micrometer:micrometer-observation
  dependency-version: 1.14.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-10 03:35:38 +00:00
Rob Winch af15d735eb Merge branch '6.3.x' into 6.4.x 2025-06-09 17:10:55 -05:00
Rob Winch e00d06e97f Merge branch 'gradle/6.4.x/org.apache.maven-maven-resolver-provider-3.9.10' into 6.4.x 2025-06-09 17:09:09 -05:00
Rob Winch e8028e15c0 Merge branch 'gradle/6.3.x/org.apache.maven-maven-resolver-provider-3.9.10' into 6.3.x 2025-06-09 17:08:30 -05:00
Rob Winch 12d479baab Merge branch '6.3.x' into 6.4.x 2025-06-09 17:05:46 -05:00
Rob Winch 362cc62611 Merge branch 'gradle/6.4.x/io.spring.develocity.conventions-0.0.23' into 6.4.x 2025-06-09 17:02:55 -05:00
Rob Winch fd2e3f43f6 Bump io-spring-javaformat from 0.0.45 to 0.0.46 2025-06-09 16:23:10 -05:00
Rob Winch 482eb0e2cd Bump io-spring-javaformat from 0.0.45 to 0.0.46 2025-06-09 16:22:15 -05:00
Rob Winch 0411986013 Bump org.hibernate.orm:hibernate-core from 6.6.15.Final to 6.6.17.Final 2025-06-09 16:16:56 -05:00
Joe Grandja a377175455 Merge branch '6.3.x' into 6.4.x
Closes gh-17215
2025-06-06 06:50:45 -04:00
Andrey Litvitski b0f8aa5ea0 Fix to allow multiple AuthenticationFilter instances to process each request
Closes gh-17173

Signed-off-by: Andrey Litvitski <andrey1010102008@gmail.com>
2025-06-06 06:37:03 -04:00
dependabot[bot] 47b6e31606 Bump org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10
Bumps org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10.

---
updated-dependencies:
- dependency-name: org.apache.maven:maven-resolver-provider
  dependency-version: 3.9.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-06 03:40:05 +00:00
dependabot[bot] f75ac6c837 Bump org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10
Bumps org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10.

---
updated-dependencies:
- dependency-name: org.apache.maven:maven-resolver-provider
  dependency-version: 3.9.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-06 03:37:31 +00:00
damable-nuvolex a0c5504eca Fix inconsistent constructor declaration
Closes gh-16325

Signed-off-by: damable-nuvolex <damable@nuvolex.com>
2025-06-05 12:34:35 -06:00
dependabot[bot] 7341e629cb Bump io.spring.develocity.conventions from 0.0.22 to 0.0.23
Bumps [io.spring.develocity.conventions](https://github.com/spring-io/develocity-conventions) from 0.0.22 to 0.0.23.
- [Release notes](https://github.com/spring-io/develocity-conventions/releases)
- [Commits](https://github.com/spring-io/develocity-conventions/compare/v0.0.22...v0.0.23)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-04 03:49:51 +00:00
dependabot[bot] b85814efcf Bump io-spring-javaformat from 0.0.45 to 0.0.46
Bumps `io-spring-javaformat` from 0.0.45 to 0.0.46.

Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.45 to 0.0.46
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46)

Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.45 to 0.0.46
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-03 03:43:40 +00:00
dependabot[bot] 5e56fc13be Bump io-spring-javaformat from 0.0.45 to 0.0.46
Bumps `io-spring-javaformat` from 0.0.45 to 0.0.46.

Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.45 to 0.0.46
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46)

Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.45 to 0.0.46
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-03 03:29:44 +00:00
dependabot[bot] 9a3d076bfd Bump org.hibernate.orm:hibernate-core from 6.6.15.Final to 6.6.17.Final
Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.15.Final to 6.6.17.Final.
- [Release notes](https://github.com/hibernate/hibernate-orm/releases)
- [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.17/changelog.txt)
- [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.15...6.6.17)

---
updated-dependencies:
- dependency-name: org.hibernate.orm:hibernate-core
  dependency-version: 6.6.17.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-29 03:39:38 +00:00
Josh Cummings 2989d12743 Merge branch '6.3.x' into 6.4.x 2025-05-23 11:35:25 -06:00
Joaquin Santana c0568ea9b0 Log Request Mismatch Only When Mismatches
Signed-off-by: Joaquin Santana <joaquinjsb@outlook.com>
2025-05-23 11:34:48 -06:00
Josh Cummings 3186e8df84 Merge remote-tracking branch 'origin/6.3.x' into 6.4.x 2025-05-21 16:46:54 -06:00
Andrey Litvitski 4048b2bd7d Use HttpStatus in BackChannel Logout Filters
Closes gh-17125

Signed-off-by: Andrey Litvitski <andrey1010102008@gmail.com>
2025-05-21 16:45:46 -06:00
dependabot[bot] e77388ca16 Bump io-spring-javaformat from 0.0.43 to 0.0.45
Bumps `io-spring-javaformat` from 0.0.43 to 0.0.45.

Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.43 to 0.0.45
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45)

Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.43 to 0.0.45
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-21 14:52:21 -06:00
Josh Cummings 22b8294f7f Merge branch '6.3.x' into 6.4.x 2025-05-21 14:51:24 -06:00
dependabot[bot] 86acba9d22 Bump io-spring-javaformat from 0.0.43 to 0.0.45
Bumps `io-spring-javaformat` from 0.0.43 to 0.0.45.

Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.43 to 0.0.45
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45)

Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.43 to 0.0.45
- [Release notes](https://github.com/spring-io/spring-javaformat/releases)
- [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-21 14:50:17 -06:00
Josh Cummings fbfb28456a Merge branch '6.3.x' into 6.4.x 2025-05-21 14:43:44 -06:00
Gurunathan a4cd6f4278 Advise Overriding equals() and hashCode() in UserDetails Implementations
This commit adds a documentation note explaining the importance of
overriding equals() and hashCode() in custom UserDetails implementations.

The default SessionRegistryImpl in Spring Security uses an in-memory
ConcurrentMap<Object, Set<String>>, Map<String,SessionInformation> to
associate principals with sessions. If a custom UserDetails class does
not properly override equals() and hashCode(), user sessions may not
be tracked or matched correctly.

I believe this helps developers avoid subtle session management issues
when implementing custom authentication logic.

Signed-off-by: Gurunathan <129361658+Gurunathan16@users.noreply.github.com>
2025-05-21 12:41:44 -06:00
Rob Winch 233a6651cc Merge branch '6.3.x' into 6.4.x 2025-05-20 15:53:04 -05:00
Rob Winch 5da31ab8a8 Use spring-io/codeql-actions 2025-05-20 15:52:36 -05:00
github-actions[bot] 4a2953fa5b Next development version 2025-05-19 16:33:25 +00:00
github-actions[bot] 3fbcd5f62a Release 6.4.6 2025-05-19 15:53:05 +00:00
Josh Cummings edc8735eb8 Merge branch '6.3.x' into 6.4.x
Closes gh-17146
2025-05-19 09:46:10 -06:00
Mark Putsiata cae3467a8d Improve AbstractPreAuthenticatedProcessingFilter docs
Clarify misleading SecurityContextRepository setter documentation.
Note that AbstractPreAuthenticatedProcessingFilter saves the
SecurityContext upon successful authentication, and this behavior
can be customized via the setSecurityContextRepository setter.

Closes gh-14137

Signed-off-by: Mark Putsiata <m.putsiata@gmail.com>
2025-05-19 09:45:53 -06:00
Josh Cummings bf2aaa1b18 Use .equals to Compare Methods
Closes gh-17143
2025-05-19 09:17:44 -06:00
Rob Winch 3690517395 Merge branch 'gradle/6.4.x/org.springframework.data-spring-data-bom-2024.1.6' into 6.4.x 2025-05-19 08:43:44 -05:00
Rob Winch d0e9128db5 Merge branch '6.3.x' into 6.4.x 2025-05-19 08:41:21 -05:00
dependabot[bot] 1864c876d1 Bump org.springframework.data:spring-data-bom from 2024.1.5 to 2024.1.6
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.5 to 2024.1.6.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.5...2024.1.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 03:51:09 +00:00
dependabot[bot] a17b2a18d9 Bump org.springframework.data:spring-data-bom
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.11 to 2024.0.12.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.11...2024.0.12)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 03:30:36 +00:00
Rob Winch 16c979460e Merge Bump org.springframework:spring-framework-bom from 6.1.19 to 6.1.20 2025-05-16 10:40:59 -05:00
Rob Winch ce08aa49f7 Merge branch '6.3.x' into 6.4.x
- Ignore Bump org.springframework:spring-framework-bom
2025-05-16 10:39:59 -05:00
dependabot[bot] 0cbc38cdd6 Bump org.springframework:spring-framework-bom from 6.1.19 to 6.1.20
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.19 to 6.1.20.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.19...v6.1.20)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-16 03:22:19 +00:00
dependabot[bot] e5d62e0bdd Bump org.springframework:spring-framework-bom from 6.2.6 to 6.2.7
Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.6 to 6.2.7.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.6...v6.2.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-16 03:15:15 +00:00
Josh Cummings 70c940fd4f Merge branch '6.3.x' into 6.4.x 2025-05-15 18:16:44 -06:00
Josh Cummings eb30fd7f59 Add Missing Header
Issue gh-11161
2025-05-15 18:16:36 -06:00
Josh Cummings fbdf4a88a0 Merge branch '6.3.x' into 6.4.x 2025-05-15 17:19:55 -06:00
snowykte0426 260d298cc5 Add Migration Guide from Spring Security SAML Extension
This adds a dedicated migration guide for users moving from the Spring Security SAML Extension to the built-in SAML 2.0 support.

Includes:
- Content migrated from the project wiki
- xref links for `saml2Login`, `saml2Logout`, and `saml2Metadata`
- Metadata example moved to Examples Matrix
- Cleanup and naming per review feedback

Closes gh-11161

Signed-off-by: snowykte0426 <snowykte0426@naver.com>
2025-05-15 17:17:43 -06:00
Rob Winch b38cf1fc16 Merge branch 'gradle/6.4.x/org.hibernate.orm-hibernate-core-6.6.15.Final' into 6.4.x 2025-05-14 11:12:24 -05:00
Rob Winch 5a2bd2b825 Merge branch '6.3.x' into 6.4.x
- Bump io.projectreactor:reactor-bom from 2023.0.17 to 2023.0.18

Closes gh-17110
2025-05-14 11:00:22 -05:00
dependabot[bot] 91afd49faf Bump org.hibernate.orm:hibernate-core from 6.6.14.Final to 6.6.15.Final
Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.14.Final to 6.6.15.Final.
- [Release notes](https://github.com/hibernate/hibernate-orm/releases)
- [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.15/changelog.txt)
- [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.14...6.6.15)

---
updated-dependencies:
- dependency-name: org.hibernate.orm:hibernate-core
  dependency-version: 6.6.15.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-14 03:33:33 +00:00
dependabot[bot] 78a60d0d84 Bump io.projectreactor:reactor-bom from 2023.0.17 to 2023.0.18
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.17 to 2023.0.18.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2023.0.17...2023.0.18)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-14 03:23:25 +00:00
dependabot[bot] d34fd236f6 Bump io.micrometer:micrometer-observation from 1.14.6 to 1.14.7
Bumps [io.micrometer:micrometer-observation](https://github.com/micrometer-metrics/micrometer) from 1.14.6 to 1.14.7.
- [Release notes](https://github.com/micrometer-metrics/micrometer/releases)
- [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.6...v1.14.7)

---
updated-dependencies:
- dependency-name: io.micrometer:micrometer-observation
  dependency-version: 1.14.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 12:30:10 -06:00
dependabot[bot] ad934efc24 Bump org.hibernate.orm:hibernate-core from 6.6.13.Final to 6.6.14.Final
Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.13.Final to 6.6.14.Final.
- [Release notes](https://github.com/hibernate/hibernate-orm/releases)
- [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.14/changelog.txt)
- [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.13...6.6.14)

---
updated-dependencies:
- dependency-name: org.hibernate.orm:hibernate-core
  dependency-version: 6.6.14.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 12:24:36 -06:00
dependabot[bot] 11eac05dfd Bump org-apache-maven-resolver from 1.9.22 to 1.9.23
Bumps `org-apache-maven-resolver` from 1.9.22 to 1.9.23.

Updates `org.apache.maven.resolver:maven-resolver-connector-basic` from 1.9.22 to 1.9.23
- [Release notes](https://github.com/apache/maven-resolver/releases)
- [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23)

Updates `org.apache.maven.resolver:maven-resolver-impl` from 1.9.22 to 1.9.23
- [Release notes](https://github.com/apache/maven-resolver/releases)
- [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23)

Updates `org.apache.maven.resolver:maven-resolver-transport-http` from 1.9.22 to 1.9.23

---
updated-dependencies:
- dependency-name: org.apache.maven.resolver:maven-resolver-connector-basic
  dependency-version: 1.9.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.maven.resolver:maven-resolver-impl
  dependency-version: 1.9.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.maven.resolver:maven-resolver-transport-http
  dependency-version: 1.9.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 12:20:38 -06:00
Josh Cummings 3a36197d7a Merge branch '6.3.x' into 6.4.x 2025-05-13 12:17:29 -06:00
dependabot[bot] a001f27690 Bump org-apache-maven-resolver from 1.9.22 to 1.9.23
Bumps `org-apache-maven-resolver` from 1.9.22 to 1.9.23.

Updates `org.apache.maven.resolver:maven-resolver-connector-basic` from 1.9.22 to 1.9.23
- [Release notes](https://github.com/apache/maven-resolver/releases)
- [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23)

Updates `org.apache.maven.resolver:maven-resolver-impl` from 1.9.22 to 1.9.23
- [Release notes](https://github.com/apache/maven-resolver/releases)
- [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23)

Updates `org.apache.maven.resolver:maven-resolver-transport-http` from 1.9.22 to 1.9.23

---
updated-dependencies:
- dependency-name: org.apache.maven.resolver:maven-resolver-connector-basic
  dependency-version: 1.9.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.maven.resolver:maven-resolver-impl
  dependency-version: 1.9.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.maven.resolver:maven-resolver-transport-http
  dependency-version: 1.9.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 12:15:42 -06:00
Josh Cummings 5ba4ab5e11 Merge branch '6.3.x' into 6.4.x 2025-05-13 11:18:02 -06:00
Danilo Piazzalunga 27319e3f9b Add missing registration property in YAML listing
Signed-off-by: Danilo Piazzalunga <danilopiazza@gmail.com>
2025-05-13 11:17:35 -06:00
Danilo Piazzalunga ec462e8bc5 Update assertingparty property usage in YAML snippets
Spring Boot 2.7 renamed spring.security.saml2.relyingparty.registration.*.identityprovider.*
to spring.security.saml2.relyingparty.registration.*.assertingparty.*.

Closes gh-12810.

Signed-off-by: Danilo Piazzalunga <danilopiazza@gmail.com>
2025-05-13 11:17:35 -06:00
dependabot[bot] 8fcf181ff0 Bump com.fasterxml.jackson:jackson-bom from 2.18.3 to 2.18.4
Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.18.3 to 2.18.4.
- [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.3...jackson-bom-2.18.4)

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson:jackson-bom
  dependency-version: 2.18.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-07 03:30:49 +00:00
dependabot[bot] dd0b26a992 Bump io.spring.gradle:spring-security-release-plugin from 1.0.5 to 1.0.6
Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.5 to 1.0.6.
- [Release notes](https://github.com/spring-io/spring-security-release-tools/releases)
- [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.5...v1.0.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-06 10:15:39 -06:00
dependabot[bot] a4111a606b Bump io.spring.gradle:spring-security-release-plugin from 1.0.5 to 1.0.6
Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.5 to 1.0.6.
- [Release notes](https://github.com/spring-io/spring-security-release-tools/releases)
- [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.5...v1.0.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-06 10:15:11 -06:00
Rob Winch 63d79a97db Merge branch '6.3.x' into 6.4.x
- Correct method name in logout.adoc

Closes gh-17048
2025-05-06 10:23:58 -05:00
Tran Ngoc Nhan 505fe3abed Correct method name
Closes gh-17031

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-05-06 10:17:29 -05:00
Josh Cummings 0220e471bb Move Serialization Samples
To make SpringSecurityCoreVersionSerializableTests more manageable,
this commit moves the sample class constructions to a separate file.
In this way, the tests file only changes when serialization tests are
added. When classes are introduced, they can be added to SerializationSamples,
separating the two concerns
2025-05-05 15:51:10 -06:00
Josh Cummings c3c2bcd6b7 Ignore Serialization in Test Components
Since we don't need to ensure the serializability of test components
across versions, we can ignore missing version UIDs when those
test components aren't about testing Java serialization.

Issue gh-17038
2025-05-05 15:09:50 -06:00
Josh Cummings 39fdceab59 Add Missing Serializable Samples
Issue gh-17038
2025-05-05 15:09:50 -06:00
Josh Cummings 65d53beff8 Polish Serialization Tests
- Error when public, non-ignored, serializable file is missing a sample
- Provide mechanism for creating an InstancioApi from scratch

Issue gh-17038
2025-05-05 15:09:49 -06:00
Josh Cummings 34afa64c0c Add Current-Version Deserialization Test
We should test that serialized files from the current minor version
can be deserialized. This ensures that serializations remain
deserializable in patch releases.

Issue gh-3737
2025-05-05 15:09:43 -06:00
Rob Winch b5e1c3770b Merge branch '6.3.x' into 6.4.x
- remove update-dependabot action
2025-05-05 13:36:01 -05:00
Rob Winch 9710492619 remove update-dependabot action 2025-05-05 13:34:16 -05:00
Rob Winch 6dc8cd1f60 Merge branch '6.3.x' into 6.4.x
- Use pull-request: write for gradlew updates
2025-05-05 13:23:35 -05:00
Rob Winch 9436796973 Use pull-request: write for gradlew updates
Explicitly provide the permissions required for updating the Gradle
wrapper
2025-05-05 11:49:08 -05:00
Josh Cummings 92160fa26f Merge branch '6.3.x' into 6.4.x
Closes gh-17034
2025-05-02 15:58:58 -06:00
Josh Cummings 51239359ed Fix ClearSiteData Code Snippet
Closes gh-16948
2025-05-02 15:57:31 -06:00
Josh Cummings 57fc29e614 Merge branch '6.3.x' into 6.4.x
Closes gh-17032
2025-05-02 10:57:55 -06:00
Josh Cummings e48f26e51e Propagate StrictFirewallRequest Wrapper
Closes gh-16978
2025-05-02 10:57:07 -06:00
Rob Winch a26a64d213 Merge branch '6.3.x' into 6.4.x
- codeql uses ubuntu-latest
2025-05-02 11:49:50 -05:00
Rob Winch 3b7e3a6c5c codeql uses ubuntu-latest 2025-05-02 11:49:41 -05:00
Rob Winch fa533ea5e2 Merge branch '6.3.x' into 6.4.x
- rm mark-duplicate-dependabot-prs.yml
2025-05-02 11:26:47 -05:00
Rob Winch a04025c114 rm mark-duplicate-dependabot-prs.yml 2025-05-02 11:26:41 -05:00
Rob Winch 99cede5e08 Merge branch '6.3.x' into 6.4.x
- Remove automerge forward
2025-05-02 11:23:14 -05:00
Rob Winch 1564076276 Remove automerge forward 2025-05-02 11:23:01 -05:00
Rob Winch 389ba794fa Merge branch '6.3.x' into 6.4.x
- Add .github/workflows/codeql.yml
2025-05-02 11:17:07 -05:00
Rob Winch ae09f36291 Add .github/workflows/codeql.yml 2025-05-02 11:15:37 -05:00
Josh Cummings c4a0dfe838 Merge remote-tracking branch 'origin/6.3.x' into 6.4.x 2025-05-01 12:03:05 -06:00
Soumik Sarker bcef6ed74f Reformatted lines in x509 overview documentation
Signed-off-by: Soumik Sarker <ronodhirsoumik@gmail.com>
2025-05-01 12:02:45 -06:00
Josh Cummings d02a9a3c46 Merge branch '6.3.x' into 6.4.x 2025-04-29 14:48:56 -06:00
github-actions[bot] c8581683da Bump Gradle Wrapper from 8.13 to 8.14.
Release notes of Gradle 8.14 can be found here:
https://docs.gradle.org/8.14/release-notes.html

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-29 14:48:42 -06:00
Josh Cummings a4126aa27d Merge branch '6.3.x' into 6.4.x 2025-04-29 14:27:40 -06:00
Josh Cummings f631a0fcd5 Polish ClientRegistrationsTests
Simplified the assertion so that it is focused on the core
behavior being verified. This will likely also make the test
more stable when updating Spring Framework versions.

Issue gh-16860
2025-04-29 14:27:04 -06:00
Josh Cummings 656ad72608 Merge branch '6.3.x' into 6.4.x
Closes gh-17016
2025-04-29 14:22:52 -06:00
Evgeniy Cheban 0e84f31a00 Add ClientRegistration's RestClient failed attempts information to exception message
Closes gh-16860

Signed-off-by: Evgeniy Cheban <mister.cheban@gmail.com>
2025-04-29 13:43:20 -06:00
Josh Cummings d76ccc6856 Merge branch '6.3.x' into 6.4.x 2025-04-29 13:38:41 -06:00
Yanming Zhou 9c76ab69f0 Use proper configuration key
the getter method is `getOpaquetoken()` not `getOpaqueToken()`

See https://github.com/spring-projects/spring-boot/blob/c6045c3111c43bd7b0f99e6c2858bfb2999e358f/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java#L51

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-04-29 13:37:51 -06:00
Josh Cummings 868342b3a9 Add OpenSAML 5 Test
Issue gh-17008
2025-04-28 11:25:31 -06:00
Josh Cummings ce000ed190 Merge branch '6.3.x' into 6.4.x
Closes gh-17008
2025-04-28 11:18:46 -06:00
Josh Cummings 5354e4d2c5 Check for Null Issuer
Closes gh-16989
2025-04-28 11:18:32 -06:00
Josh Cummings e6957bb854 Merge branch '6.3.x' into 6.4.x 2025-04-28 11:13:09 -06:00
Rob Winch db48d4ca50 rm merge-dependabot-pr.yml from Unsupported Branch 2025-04-25 13:17:14 -05:00
Josh Cummings 547d174f3e Fix Formatting 2025-04-24 10:43:03 -06:00
Roman Trapickin d2d1275b39 Fix IllegalArgumentException message for unknown Argon2 types
Array index 0 points to an empty string. Use index 1 instead.

Signed-off-by: Roman Trapickin <8594293+rntrp@users.noreply.github.com>
2025-04-24 10:43:03 -06:00
dependabot[bot] 54cd987dbc Bump org.springframework.data:spring-data-bom from 2024.1.4 to 2024.1.5
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.4 to 2024.1.5.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.4...2024.1.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-22 20:55:32 -07:00
github-actions[bot] 9495a332bc Merge branch '6.3.x' into 6.4.x 2025-04-23 03:50:20 +00:00
dependabot[bot] 7bf776ec38 Bump org.springframework.data:spring-data-bom
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.10 to 2024.0.11.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.10...2024.0.11)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-22 20:49:38 -07:00
Rob Winch 1ccd600a18 Merge branch '6.3.x' into 6.4.x
- Update to io.spring.gradle:spring-security-release-plugin:1.0.5

Closes gh-6.3.10 in 6.4.x
2025-04-21 13:45:44 -05:00
Rob Winch 7a302a9eb8 Merge branch '6.3.x' (early part) into 6.4.x 2025-04-21 13:45:38 -05:00
Rob Winch e47a6714a5 Update to io.spring.gradle:spring-security-release-plugin:1.0.5
Closes gh-6.3.10
2025-04-21 13:44:10 -05:00
github-actions[bot] a4d7ac24c8 Next development version 2025-04-21 16:28:51 +00:00
github-actions[bot] b9cae82b89 Next development version 2025-04-21 16:26:30 +00:00
github-actions[bot] f6354250a1 Release 6.3.9 2025-04-21 15:58:56 +00:00
54 changed files with 1021 additions and 978 deletions
-40
View File
@@ -1,40 +0,0 @@
version: 2
registries:
spring-milestones:
type: maven-repository
url: https://repo.spring.io/milestone
updates:
- package-ecosystem: "gradle"
target-branch: "main"
directory: "/"
schedule:
interval: "daily"
time: "03:00"
timezone: "Etc/UTC"
labels: [ "type: dependency-upgrade" ]
registries:
- "spring-milestones"
ignore:
- dependency-name: "com.nimbusds:nimbus-jose-jwt" # nimbus-jose-jwt gets updated when oauth2-oidc-sdk is updated to ensure consistency
- dependency-name: "org.python:jython" # jython updates break integration tests
- dependency-name: "org.apache.directory.server:*" # ApacheDS version > 1.5.5 contains break changes
- dependency-name: "org.junit:junit-bom"
update-types: [ "version-update:semver-major" ]
- dependency-name: "org.mockito:mockito-bom"
update-types: [ "version-update:semver-major" ]
- dependency-name: "*"
update-types: [ "version-update:semver-major", "version-update:semver-minor" ]
# GitHub Actions
- package-ecosystem: github-actions
target-branch: "main"
directory: "/"
schedule:
interval: weekly
ignore:
- dependency-name: "spring-io/*"
- dependency-name: "spring-security-release-tools/*"
+17
View File
@@ -0,0 +1,17 @@
name: "CodeQL Advanced"
on:
push:
pull_request:
workflow_dispatch:
schedule:
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule
- cron: '0 5 * * *'
permissions: read-all
jobs:
codeql-analysis-call:
permissions:
actions: read
contents: read
security-events: write
uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@1
@@ -1,57 +0,0 @@
name: Auto Merge Forward Dependabot Commits
on:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: dependabot-auto-merge-forward
jobs:
get-supported-branches:
uses: spring-io/spring-security-release-tools/.github/workflows/retrieve-spring-supported-versions.yml@actions-v1
with:
project: spring-security
type: oss
repository_name: spring-projects/spring-security
auto-merge-forward-dependabot:
name: Auto Merge Forward Dependabot Commits
runs-on: ubuntu-latest
needs: [get-supported-branches]
permissions:
contents: write
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Setup GitHub User
id: setup-gh-user
run: |
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
- name: Run Auto Merge Forward
id: run-auto-merge-forward
uses: spring-io/spring-security-release-tools/.github/actions/auto-merge-forward@actions-v1
with:
branches: ${{ needs.get-supported-branches.outputs.supported_versions }},main
from-author: dependabot[bot]
notify_result:
name: Check for failures
needs: [ auto-merge-forward-dependabot ]
if: failure()
runs-on: ubuntu-latest
permissions:
actions: read
steps:
- name: Send Slack message
uses: Gamesight/slack-workflow-status@v1.3.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#spring-security-ci'
name: 'CI Notifier'
@@ -4,7 +4,8 @@ on:
schedule:
- cron: '0 2 * * *' # 2am UTC
workflow_dispatch:
permissions:
pull-requests: write
jobs:
upgrade_wrapper:
name: Execution
@@ -1,45 +0,0 @@
name: Mark Duplicate Dependabot PRs
on:
pull_request:
types: [closed]
jobs:
check_duplicate_prs:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true && github.event.pull_request.user.login == 'dependabot[bot]'
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Extract Dependency Name from PR Title
id: extract
run: |
PR_TITLE="${{ github.event.pull_request.title }}"
DEPENDENCY_NAME=$(echo "$PR_TITLE" | awk -F ' from ' '{print $1}')
echo "dependency_name=$DEPENDENCY_NAME" >> $GITHUB_OUTPUT
- name: Find PRs
id: find_duplicates
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PRS=$(gh pr list --search 'milestone:${{ github.event.pull_request.milestone.title }} is:merged in:title "${{ steps.extract.outputs.dependency_name }}"' --json number --jq 'map(.number) | join(",")')
echo "prs=$PRS" >> $GITHUB_OUTPUT
- name: Label Duplicate PRs
if: steps.find_duplicates.outputs.prs != ''
env:
PRS: ${{ steps.find_duplicates.outputs.prs }}
CURRENT_PR_NUMBER: ${{ github.event.pull_request.number }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
for i in ${PRS//,/ }
do
if [ ! $i -eq "$CURRENT_PR_NUMBER" ]; then
echo "Marking PR $i as duplicate"
gh pr edit "$i" --add-label "status: duplicate"
gh pr comment "$i" --body "Duplicate of #$CURRENT_PR_NUMBER"
fi
done
-63
View File
@@ -1,63 +0,0 @@
name: Merge Dependabot PR
on: pull_request_target
run-name: Merge Dependabot PR ${{ github.ref_name }}
permissions: write-all
jobs:
merge-dependabot-pr:
name: Merge Dependabot PR
runs-on: ubuntu-latest
if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@v4
with:
show-progress: false
ref: ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set Milestone to Dependabot Pull Request
id: set-milestone
run: |
if test -f pom.xml
then
CURRENT_VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout)
else
CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }')
fi
export CANDIDATE_VERSION=${CURRENT_VERSION/-SNAPSHOT}
MILESTONE=$(gh api repos/$GITHUB_REPOSITORY/milestones --jq 'map(select(.due_on != null and (.title | startswith(env.CANDIDATE_VERSION)))) | .[0] | .title')
if [ -z $MILESTONE ]
then
gh run cancel ${{ github.run_id }}
echo "::warning title=Cannot merge::No scheduled milestone for $CURRENT_VERSION version"
else
gh pr edit ${{ github.event.pull_request.number }} --milestone $MILESTONE
echo mergeEnabled=true >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Merge Dependabot pull request
if: steps.set-milestone.outputs.mergeEnabled
run: gh pr merge ${{ github.event.pull_request.number }} --auto --rebase
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
send-notification:
name: Send Notification
needs: [ merge-dependabot-pr ]
if: ${{ failure() || cancelled() }}
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
@@ -1,22 +0,0 @@
name: Trigger Dependabot Auto Merge Forward
on:
push:
branches:
- '*.x'
permissions: read-all
jobs:
trigger-worflow:
name: Trigger Workflow
runs-on: ubuntu-latest
if: ${{ github.event.commits[0].author.username == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }}
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
- id: trigger
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run dependabot-auto-merge-forward.yml -r main
-36
View File
@@ -1,36 +0,0 @@
name: Update dependabot.yml
on:
workflow_dispatch:
permissions:
contents: read
jobs:
get-supported-branches:
uses: spring-io/spring-security-release-tools/.github/workflows/retrieve-spring-supported-versions.yml@actions-v1
with:
project: spring-security
type: oss
repository_name: spring-projects/spring-security
main:
runs-on: ubuntu-latest
needs: [get-supported-branches]
if: ${{ (github.repository == 'spring-projects/spring-security') && (github.ref == 'refs/heads/main') }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: spring-io/spring-security-release-tools/.github/actions/generate-dependabot-yml@actions-v1
name: Update dependabot.yml
with:
gradle-branches: ${{ needs.get-supported-branches.outputs.supported_versions }},main
github-actions-branches: ${{ needs.get-supported-branches.outputs.supported_versions }},main,docs-build
gh-token: ${{ secrets.GITHUB_TOKEN }}
- uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: Update dependabot.yml
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@@ -144,7 +144,7 @@ public class PreAuthorizeAspectTests {
protected void protectedMethod() {
}
@PreAuthorize("hasRole('X')")
@PreAuthorize("hasRole('A')")
void publicCallsPrivate() {
privateMethod();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@@ -83,10 +83,11 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration
private final AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor;
@Autowired(required = false)
ReactiveAuthorizationManagerMethodSecurityConfiguration(MethodSecurityExpressionHandler expressionHandler,
ReactiveAuthorizationManagerMethodSecurityConfiguration(
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlers,
ObjectProvider<ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocation>>> preAuthorizePostProcessor,
ObjectProvider<ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocationResult>>> postAuthorizePostProcessor) {
MethodSecurityExpressionHandler expressionHandler = expressionHandlers.getIfUnique();
if (expressionHandler != null) {
this.preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
this.preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(expressionHandler);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,12 +18,12 @@ package org.springframework.security.config.web.server;
import java.util.Collections;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.HttpMessageWriter;
@@ -47,6 +47,7 @@ import org.springframework.web.server.WebFilterChain;
* A filter for the Client-side OIDC Back-Channel Logout endpoint
*
* @author Josh Cummings
* @author Andrey Litvitski
* @since 6.2
* @see <a target="_blank" href=
* "https://openid.net/specs/openid-connect-backchannel-1_0.html">OIDC Back-Channel Logout
@@ -108,7 +109,7 @@ class OidcBackChannelLogoutWebFilter implements WebFilter {
private Mono<Void> handleAuthenticationFailure(ServerWebExchange exchange, Exception ex) {
this.logger.debug("Failed to process OIDC Back-Channel Logout", ex);
exchange.getResponse().setRawStatusCode(HttpServletResponse.SC_BAD_REQUEST);
exchange.getResponse().setRawStatusCode(HttpStatus.BAD_REQUEST.value());
return this.errorHttpMessageConverter.write(Mono.just(oauth2Error(ex)), ResolvableType.forClass(Object.class),
ResolvableType.forClass(Object.class), MediaType.APPLICATION_JSON, exchange.getRequest(),
exchange.getResponse(), Collections.emptyMap());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,13 +22,13 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.EncoderHttpMessageWriter;
@@ -54,7 +54,8 @@ import org.springframework.web.util.UriComponentsBuilder;
* Back-Channel Logout Token and invalidates each one.
*
* @author Josh Cummings
* @since 6.4
* @author Andrey Litvitski
* @since 6.2
* @see <a target="_blank" href=
* "https://openid.net/specs/openid-connect-backchannel-1_0.html">OIDC Back-Channel Logout
* Spec</a>
@@ -170,7 +171,7 @@ public final class OidcBackChannelServerLogoutHandler implements ServerLogoutHan
}
private Mono<Void> handleLogoutFailure(ServerWebExchange exchange, OAuth2Error error) {
exchange.getResponse().setRawStatusCode(HttpServletResponse.SC_BAD_REQUEST);
exchange.getResponse().setRawStatusCode(HttpStatus.BAD_REQUEST.value());
return this.errorHttpMessageConverter.write(Mono.just(error), ResolvableType.forClass(Object.class),
ResolvableType.forClass(Object.class), MediaType.APPLICATION_JSON, exchange.getRequest(),
exchange.getResponse(), Collections.emptyMap());
@@ -0,0 +1,700 @@
/*
* Copyright 2002-2025 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;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.time.Instant;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;
import jakarta.servlet.http.Cookie;
import org.apereo.cas.client.validation.AssertionImpl;
import org.instancio.Instancio;
import org.instancio.InstancioApi;
import org.instancio.InstancioOfClassApi;
import org.instancio.Select;
import org.instancio.generator.Generator;
import org.springframework.core.ResolvableType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException;
import org.springframework.security.access.intercept.RunAsUserToken;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.ProviderNotFoundException;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent;
import org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent;
import org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent;
import org.springframework.security.authentication.event.AuthenticationFailureLockedEvent;
import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent;
import org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent;
import org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.authentication.event.LogoutSuccessEvent;
import org.springframework.security.authentication.jaas.JaasAuthenticationToken;
import org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent;
import org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent;
import org.springframework.security.authentication.ott.DefaultOneTimeToken;
import org.springframework.security.authentication.ott.InvalidOneTimeTokenException;
import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken;
import org.springframework.security.authentication.password.CompromisedPasswordException;
import org.springframework.security.authorization.AuthorityAuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.event.AuthorizationEvent;
import org.springframework.security.authorization.event.AuthorizationGrantedEvent;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken;
import org.springframework.security.config.annotation.AlreadyBuiltException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.context.TransientSecurityContext;
import org.springframework.security.core.session.AbstractSessionEvent;
import org.springframework.security.core.session.ReactiveSessionInformation;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.ldap.ppolicy.PasswordPolicyControl;
import org.springframework.security.ldap.ppolicy.PasswordPolicyErrorStatus;
import org.springframework.security.ldap.ppolicy.PasswordPolicyException;
import org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl;
import org.springframework.security.ldap.userdetails.LdapAuthority;
import org.springframework.security.oauth2.client.ClientAuthorizationException;
import org.springframework.security.oauth2.client.ClientAuthorizationRequiredException;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens;
import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens;
import org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken;
import org.springframework.security.oauth2.client.oidc.authentication.logout.TestOidcLogoutTokens;
import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation;
import org.springframework.security.oauth2.client.oidc.session.TestOidcSessionInformations;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
import org.springframework.security.oauth2.core.OAuth2DeviceCode;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.OAuth2UserCode;
import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipals;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
import org.springframework.security.oauth2.core.oidc.TestOidcIdTokens;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
import org.springframework.security.oauth2.core.oidc.user.TestOidcUsers;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import org.springframework.security.oauth2.core.user.TestOAuth2Users;
import org.springframework.security.oauth2.jwt.BadJwtException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoderInitializationException;
import org.springframework.security.oauth2.jwt.JwtEncodingException;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.oauth2.jwt.JwtValidationException;
import org.springframework.security.oauth2.jwt.TestJwts;
import org.springframework.security.oauth2.server.resource.BearerTokenError;
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
import org.springframework.security.saml2.Saml2Exception;
import org.springframework.security.saml2.core.Saml2Error;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal;
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationTokens;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2Authentications;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2LogoutRequests;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2PostAuthenticationRequests;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2RedirectAuthenticationRequests;
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException;
import org.springframework.security.web.authentication.rememberme.CookieTheftException;
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.security.web.authentication.session.SessionFixationProtectionEvent;
import org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent;
import org.springframework.security.web.authentication.www.NonceExpiredException;
import org.springframework.security.web.csrf.CsrfException;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.csrf.InvalidCsrfTokenException;
import org.springframework.security.web.csrf.MissingCsrfTokenException;
import org.springframework.security.web.firewall.RequestRejectedException;
import org.springframework.security.web.savedrequest.DefaultSavedRequest;
import org.springframework.security.web.savedrequest.SimpleSavedRequest;
import org.springframework.security.web.server.firewall.ServerExchangeRejectedException;
import org.springframework.security.web.session.HttpSessionCreatedEvent;
import org.springframework.security.web.session.HttpSessionIdChangedEvent;
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
import org.springframework.security.web.webauthn.api.Bytes;
import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput;
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInputs;
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs;
import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.PublicKeyCredential;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses;
import org.springframework.security.web.webauthn.api.TestBytes;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredential;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication;
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken;
import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest;
import org.springframework.util.ReflectionUtils;
final class SerializationSamples {
static final Map<Class<?>, Generator<?>> generatorByClassName = new HashMap<>();
static final Map<Class<?>, Supplier<InstancioApi<?>>> instancioByClassName = new HashMap<>();
static {
UserDetails user = TestAuthentication.user();
Authentication authentication = TestAuthentication.authenticated(user);
SecurityContext securityContext = new SecurityContextImpl(authentication);
// oauth2-core
generatorByClassName.put(DefaultOAuth2User.class, (r) -> TestOAuth2Users.create());
generatorByClassName.put(OAuth2AuthorizationRequest.class,
(r) -> TestOAuth2AuthorizationRequests.request().build());
generatorByClassName.put(OAuth2AuthorizationResponse.class,
(r) -> TestOAuth2AuthorizationResponses.success().build());
generatorByClassName.put(OAuth2UserAuthority.class, (r) -> new OAuth2UserAuthority(Map.of("username", "user")));
generatorByClassName.put(OAuth2AuthorizationExchange.class, (r) -> TestOAuth2AuthorizationExchanges.success());
generatorByClassName.put(OidcUserInfo.class, (r) -> OidcUserInfo.builder().email("email@example.com").build());
generatorByClassName.put(SessionInformation.class,
(r) -> new SessionInformation(user, r.alphanumeric(4), new Date(1704378933936L)));
generatorByClassName.put(ReactiveSessionInformation.class,
(r) -> new ReactiveSessionInformation(user, r.alphanumeric(4), Instant.ofEpochMilli(1704378933936L)));
generatorByClassName.put(OAuth2AccessToken.class, (r) -> TestOAuth2AccessTokens.scopes("scope"));
generatorByClassName.put(OAuth2DeviceCode.class,
(r) -> new OAuth2DeviceCode("token", Instant.now(), Instant.now()));
generatorByClassName.put(OAuth2RefreshToken.class,
(r) -> new OAuth2RefreshToken("refreshToken", Instant.now(), Instant.now()));
generatorByClassName.put(OAuth2UserCode.class,
(r) -> new OAuth2UserCode("token", Instant.now(), Instant.now()));
generatorByClassName.put(DefaultOidcUser.class, (r) -> TestOidcUsers.create());
generatorByClassName.put(OidcUserAuthority.class,
(r) -> new OidcUserAuthority(TestOidcIdTokens.idToken().build(),
new OidcUserInfo(Map.of("claim", "value")), "claim"));
generatorByClassName.put(OAuth2AuthenticationException.class,
(r) -> new OAuth2AuthenticationException(new OAuth2Error("error", "description", "uri"), "message",
new RuntimeException()));
generatorByClassName.put(OAuth2AuthorizationException.class,
(r) -> new OAuth2AuthorizationException(new OAuth2Error("error", "description", "uri"), "message",
new RuntimeException()));
// oauth2-client
ClientRegistration.Builder clientRegistrationBuilder = TestClientRegistrations.clientRegistration();
ClientRegistration clientRegistration = clientRegistrationBuilder.build();
WebAuthenticationDetails details = new WebAuthenticationDetails("remote", "sessionId");
generatorByClassName.put(ClientRegistration.class, (r) -> clientRegistration);
generatorByClassName.put(ClientRegistration.ProviderDetails.class,
(r) -> clientRegistration.getProviderDetails());
generatorByClassName.put(ClientRegistration.ProviderDetails.UserInfoEndpoint.class,
(r) -> clientRegistration.getProviderDetails().getUserInfoEndpoint());
generatorByClassName.put(ClientRegistration.Builder.class, (r) -> clientRegistrationBuilder);
generatorByClassName.put(OAuth2AuthorizedClient.class,
(r) -> new OAuth2AuthorizedClient(clientRegistration, "principal", TestOAuth2AccessTokens.noScopes()));
generatorByClassName.put(OAuth2LoginAuthenticationToken.class, (r) -> {
var token = new OAuth2LoginAuthenticationToken(clientRegistration,
TestOAuth2AuthorizationExchanges.success());
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2AuthorizationCodeAuthenticationToken.class, (r) -> {
var token = TestOAuth2AuthorizationCodeAuthenticationTokens.authenticated();
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2AuthenticationToken.class, (r) -> {
var token = TestOAuth2AuthenticationTokens.authenticated();
token.setDetails(details);
return token;
});
generatorByClassName.put(OidcIdToken.class, (r) -> TestOidcIdTokens.idToken().build());
generatorByClassName.put(OidcLogoutToken.class,
(r) -> TestOidcLogoutTokens.withSessionId("issuer", "sessionId").issuedAt(Instant.now()).build());
generatorByClassName.put(OidcSessionInformation.class, (r) -> TestOidcSessionInformations.create());
generatorByClassName.put(DefaultOAuth2AuthenticatedPrincipal.class, (r) -> {
OAuth2AuthenticatedPrincipal principal = TestOAuth2AuthenticatedPrincipals.active();
return new DefaultOAuth2AuthenticatedPrincipal(principal.getName(), principal.getAttributes(),
(Collection<GrantedAuthority>) principal.getAuthorities());
});
generatorByClassName.put(ClientAuthorizationException.class,
(r) -> new ClientAuthorizationException(new OAuth2Error("error", "description", "uri"), "id", "message",
new RuntimeException()));
generatorByClassName.put(ClientAuthorizationRequiredException.class,
(r) -> new ClientAuthorizationRequiredException("id"));
// oauth2-jose
generatorByClassName.put(BadJwtException.class, (r) -> new BadJwtException("token", new RuntimeException()));
generatorByClassName.put(JwtDecoderInitializationException.class,
(r) -> new JwtDecoderInitializationException("message", new RuntimeException()));
generatorByClassName.put(JwtEncodingException.class,
(r) -> new JwtEncodingException("message", new RuntimeException()));
generatorByClassName.put(JwtException.class, (r) -> new JwtException("message", new RuntimeException()));
generatorByClassName.put(JwtValidationException.class,
(r) -> new JwtValidationException("message", List.of(new OAuth2Error("error", "description", "uri"))));
// oauth2-jwt
generatorByClassName.put(Jwt.class, (r) -> TestJwts.user());
// oauth2-resource-server
generatorByClassName
.put(org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken.class, (r) -> {
var token = new org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken(
"token");
token.setDetails(details);
return token;
});
generatorByClassName.put(BearerTokenAuthenticationToken.class, (r) -> {
var token = new BearerTokenAuthenticationToken("token");
token.setDetails(details);
return token;
});
generatorByClassName.put(BearerTokenAuthentication.class, (r) -> {
var token = new BearerTokenAuthentication(TestOAuth2AuthenticatedPrincipals.active(),
TestOAuth2AccessTokens.noScopes(), user.getAuthorities());
token.setDetails(details);
return token;
});
generatorByClassName.put(JwtAuthenticationToken.class, (r) -> {
var token = new JwtAuthenticationToken(TestJwts.user());
token.setDetails(details);
return token;
});
generatorByClassName.put(BearerTokenError.class, (r) -> BearerTokenErrors.invalidToken("invalid token"));
generatorByClassName.put(OAuth2IntrospectionAuthenticatedPrincipal.class,
(r) -> TestOAuth2AuthenticatedPrincipals.active());
generatorByClassName.put(InvalidBearerTokenException.class,
(r) -> new InvalidBearerTokenException("description", new RuntimeException()));
generatorByClassName.put(BadOpaqueTokenException.class,
(r) -> new BadOpaqueTokenException("message", new RuntimeException()));
generatorByClassName.put(OAuth2IntrospectionException.class,
(r) -> new OAuth2IntrospectionException("message", new RuntimeException()));
// config
generatorByClassName.put(AlreadyBuiltException.class, (r) -> new AlreadyBuiltException("message"));
// core
generatorByClassName.put(RunAsUserToken.class, (r) -> {
RunAsUserToken token = new RunAsUserToken("key", user, "creds", user.getAuthorities(),
AnonymousAuthenticationToken.class);
token.setDetails(details);
return token;
});
generatorByClassName.put(RememberMeAuthenticationToken.class, (r) -> {
RememberMeAuthenticationToken token = new RememberMeAuthenticationToken("key", user, user.getAuthorities());
token.setDetails(details);
return token;
});
generatorByClassName.put(UsernamePasswordAuthenticationToken.class, (r) -> {
var token = UsernamePasswordAuthenticationToken.unauthenticated(user, "creds");
token.setDetails(details);
return token;
});
generatorByClassName.put(JaasAuthenticationToken.class, (r) -> {
var token = new JaasAuthenticationToken(user, "creds", null);
token.setDetails(details);
return token;
});
generatorByClassName.put(OneTimeTokenAuthenticationToken.class,
(r) -> applyDetails(new OneTimeTokenAuthenticationToken("username", "token")));
generatorByClassName.put(AccessDeniedException.class,
(r) -> new AccessDeniedException("access denied", new RuntimeException()));
generatorByClassName.put(AuthorizationServiceException.class,
(r) -> new AuthorizationServiceException("access denied", new RuntimeException()));
generatorByClassName.put(AccountExpiredException.class,
(r) -> new AccountExpiredException("error", new RuntimeException()));
generatorByClassName.put(AuthenticationCredentialsNotFoundException.class,
(r) -> new AuthenticationCredentialsNotFoundException("error", new RuntimeException()));
generatorByClassName.put(AuthenticationServiceException.class,
(r) -> new AuthenticationServiceException("error", new RuntimeException()));
generatorByClassName.put(BadCredentialsException.class,
(r) -> new BadCredentialsException("error", new RuntimeException()));
generatorByClassName.put(CredentialsExpiredException.class,
(r) -> new CredentialsExpiredException("error", new RuntimeException()));
generatorByClassName.put(DisabledException.class,
(r) -> new DisabledException("error", new RuntimeException()));
generatorByClassName.put(InsufficientAuthenticationException.class,
(r) -> new InsufficientAuthenticationException("error", new RuntimeException()));
generatorByClassName.put(InternalAuthenticationServiceException.class,
(r) -> new InternalAuthenticationServiceException("error", new RuntimeException()));
generatorByClassName.put(LockedException.class, (r) -> new LockedException("error", new RuntimeException()));
generatorByClassName.put(ProviderNotFoundException.class, (r) -> new ProviderNotFoundException("error"));
generatorByClassName.put(InvalidOneTimeTokenException.class, (r) -> new InvalidOneTimeTokenException("error"));
generatorByClassName.put(CompromisedPasswordException.class,
(r) -> new CompromisedPasswordException("error", new RuntimeException()));
generatorByClassName.put(UsernameNotFoundException.class,
(r) -> new UsernameNotFoundException("error", new RuntimeException()));
generatorByClassName.put(TestingAuthenticationToken.class,
(r) -> applyDetails(new TestingAuthenticationToken("username", "password")));
generatorByClassName.put(AuthenticationFailureBadCredentialsEvent.class,
(r) -> new AuthenticationFailureBadCredentialsEvent(authentication,
new BadCredentialsException("message")));
generatorByClassName.put(AuthenticationFailureCredentialsExpiredEvent.class,
(r) -> new AuthenticationFailureCredentialsExpiredEvent(authentication,
new CredentialsExpiredException("message")));
generatorByClassName.put(AuthenticationFailureDisabledEvent.class,
(r) -> new AuthenticationFailureDisabledEvent(authentication, new DisabledException("message")));
generatorByClassName.put(AuthenticationFailureExpiredEvent.class,
(r) -> new AuthenticationFailureExpiredEvent(authentication, new AccountExpiredException("message")));
generatorByClassName.put(AuthenticationFailureLockedEvent.class,
(r) -> new AuthenticationFailureLockedEvent(authentication, new LockedException("message")));
generatorByClassName.put(AuthenticationFailureProviderNotFoundEvent.class,
(r) -> new AuthenticationFailureProviderNotFoundEvent(authentication,
new ProviderNotFoundException("message")));
generatorByClassName.put(AuthenticationFailureProxyUntrustedEvent.class,
(r) -> new AuthenticationFailureProxyUntrustedEvent(authentication,
new AuthenticationServiceException("message")));
generatorByClassName.put(AuthenticationFailureServiceExceptionEvent.class,
(r) -> new AuthenticationFailureServiceExceptionEvent(authentication,
new AuthenticationServiceException("message")));
generatorByClassName.put(AuthenticationSuccessEvent.class,
(r) -> new AuthenticationSuccessEvent(authentication));
generatorByClassName.put(InteractiveAuthenticationSuccessEvent.class,
(r) -> new InteractiveAuthenticationSuccessEvent(authentication, Authentication.class));
generatorByClassName.put(LogoutSuccessEvent.class, (r) -> new LogoutSuccessEvent(authentication));
generatorByClassName.put(JaasAuthenticationFailedEvent.class,
(r) -> new JaasAuthenticationFailedEvent(authentication, new RuntimeException("message")));
generatorByClassName.put(JaasAuthenticationSuccessEvent.class,
(r) -> new JaasAuthenticationSuccessEvent(authentication));
generatorByClassName.put(AbstractSessionEvent.class, (r) -> new AbstractSessionEvent(securityContext));
generatorByClassName.put(SecurityConfig.class, (r) -> new SecurityConfig("value"));
generatorByClassName.put(TransientSecurityContext.class, (r) -> new TransientSecurityContext(authentication));
generatorByClassName.put(AuthorizationDeniedException.class,
(r) -> new AuthorizationDeniedException("message", new AuthorizationDecision(false)));
generatorByClassName.put(AuthorizationDecision.class, (r) -> new AuthorizationDecision(true));
generatorByClassName.put(AuthorityAuthorizationDecision.class,
(r) -> new AuthorityAuthorizationDecision(true, AuthorityUtils.createAuthorityList("ROLE_USER")));
generatorByClassName.put(CycleInRoleHierarchyException.class, (r) -> new CycleInRoleHierarchyException());
generatorByClassName.put(AuthorizationEvent.class,
(r) -> new AuthorizationEvent(new SerializableSupplier<>(authentication), "source",
new AuthorizationDecision(true)));
generatorByClassName.put(AuthorizationGrantedEvent.class,
(r) -> new AuthorizationGrantedEvent<>(new SerializableSupplier<>(authentication), "source",
new AuthorizationDecision(true)));
instancioByClassName.put(AuthorizationGrantedEvent.class, () -> {
InstancioOfClassApi<?> instancio = Instancio.of(AuthorizationGrantedEvent.class);
instancio.withTypeParameters(String.class);
instancio.supply(Select.all(AuthorizationGrantedEvent.class),
generatorByClassName.get(AuthorizationGrantedEvent.class));
return instancio;
});
// cas
generatorByClassName.put(CasServiceTicketAuthenticationToken.class, (r) -> {
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless("creds");
token.setDetails(details);
return token;
});
generatorByClassName.put(CasAuthenticationToken.class, (r) -> {
var token = new CasAuthenticationToken("key", user, "Password", user.getAuthorities(), user,
new AssertionImpl("test"));
token.setDetails(details);
return token;
});
generatorByClassName.put(CasAssertionAuthenticationToken.class, (r) -> {
var token = new CasAssertionAuthenticationToken(new AssertionImpl("test"), "ticket");
token.setDetails(details);
return token;
});
// ldap
generatorByClassName.put(LdapAuthority.class,
(r) -> new LdapAuthority("USER", "username", Map.of("attribute", List.of("value1", "value2"))));
generatorByClassName.put(PasswordPolicyException.class,
(r) -> new PasswordPolicyException(PasswordPolicyErrorStatus.INSUFFICIENT_PASSWORD_QUALITY));
generatorByClassName.put(PasswordPolicyControl.class, (r) -> new PasswordPolicyControl(true));
generatorByClassName.put(PasswordPolicyResponseControl.class, (r) -> {
byte[] encodedResponse = { 0x30, 0x05, (byte) 0xA0, 0x03, (byte) 0xA0, 0x1, 0x21 };
return new PasswordPolicyResponseControl(encodedResponse);
});
// saml2-service-provider
generatorByClassName.put(Saml2AuthenticationException.class,
(r) -> new Saml2AuthenticationException(new Saml2Error("code", "descirption"), "message",
new IOException("fail")));
generatorByClassName.put(Saml2Exception.class, (r) -> new Saml2Exception("message", new IOException("fail")));
generatorByClassName.put(DefaultSaml2AuthenticatedPrincipal.class,
(r) -> TestSaml2Authentications.authentication().getPrincipal());
generatorByClassName.put(Saml2Authentication.class,
(r) -> applyDetails(TestSaml2Authentications.authentication()));
generatorByClassName.put(Saml2PostAuthenticationRequest.class,
(r) -> TestSaml2PostAuthenticationRequests.create());
generatorByClassName.put(Saml2RedirectAuthenticationRequest.class,
(r) -> TestSaml2RedirectAuthenticationRequests.create());
generatorByClassName.put(Saml2X509Credential.class,
(r) -> TestSaml2X509Credentials.relyingPartyVerifyingCredential());
generatorByClassName.put(RelyingPartyRegistration.AssertingPartyDetails.class,
(r) -> TestRelyingPartyRegistrations.full().build().getAssertingPartyMetadata());
generatorByClassName.put(RelyingPartyRegistration.class, (r) -> TestRelyingPartyRegistrations.full().build());
generatorByClassName.put(Saml2AuthenticationToken.class, (r) -> {
Saml2AuthenticationToken token = TestSaml2AuthenticationTokens.tokenRequested();
token.setDetails(details);
return token;
});
generatorByClassName.put(Saml2LogoutRequest.class, (r) -> TestSaml2LogoutRequests.create());
// web
generatorByClassName.put(AnonymousAuthenticationToken.class, (r) -> {
Collection<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER");
return applyDetails(new AnonymousAuthenticationToken("key", "username", authorities));
});
generatorByClassName.put(PreAuthenticatedAuthenticationToken.class, (r) -> {
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(user, "creds",
user.getAuthorities());
token.setDetails(details);
return token;
});
generatorByClassName.put(PreAuthenticatedCredentialsNotFoundException.class,
(r) -> new PreAuthenticatedCredentialsNotFoundException("message", new IOException("fail")));
generatorByClassName.put(CookieTheftException.class, (r) -> new CookieTheftException("message"));
generatorByClassName.put(InvalidCookieException.class, (r) -> new InvalidCookieException("message"));
generatorByClassName.put(RememberMeAuthenticationException.class,
(r) -> new RememberMeAuthenticationException("message", new IOException("fail")));
generatorByClassName.put(SessionAuthenticationException.class,
(r) -> new SessionAuthenticationException("message"));
generatorByClassName.put(NonceExpiredException.class,
(r) -> new NonceExpiredException("message", new IOException("fail")));
generatorByClassName.put(CsrfException.class, (r) -> new CsrfException("message"));
generatorByClassName.put(org.springframework.security.web.server.csrf.CsrfException.class,
(r) -> new org.springframework.security.web.server.csrf.CsrfException("message"));
generatorByClassName.put(InvalidCsrfTokenException.class,
(r) -> new InvalidCsrfTokenException(new DefaultCsrfToken("header", "parameter", "token"), "token"));
generatorByClassName.put(MissingCsrfTokenException.class, (r) -> new MissingCsrfTokenException("token"));
generatorByClassName.put(DefaultCsrfToken.class, (r) -> new DefaultCsrfToken("header", "parameter", "token"));
generatorByClassName.put(org.springframework.security.web.server.csrf.DefaultCsrfToken.class,
(r) -> new org.springframework.security.web.server.csrf.DefaultCsrfToken("header", "parameter",
"token"));
generatorByClassName.put(RequestRejectedException.class, (r) -> new RequestRejectedException("message"));
generatorByClassName.put(ServerExchangeRejectedException.class,
(r) -> new ServerExchangeRejectedException("message"));
generatorByClassName.put(SessionFixationProtectionEvent.class,
(r) -> new SessionFixationProtectionEvent(authentication, "old", "new"));
generatorByClassName.put(AuthenticationSwitchUserEvent.class,
(r) -> new AuthenticationSwitchUserEvent(authentication, user));
generatorByClassName.put(HttpSessionCreatedEvent.class,
(r) -> new HttpSessionCreatedEvent(new MockHttpSession()));
generatorByClassName.put(SimpleSavedRequest.class, (r) -> {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/uri");
request.setQueryString("query=string");
request.setScheme("https");
request.setServerName("localhost");
request.setServerPort(80);
request.setRequestURI("/uri");
request.setCookies(new Cookie("name", "value"));
request.addHeader("header", "value");
request.addParameter("parameter", "value");
request.setPathInfo("/path");
request.addPreferredLocale(Locale.ENGLISH);
return new SimpleSavedRequest(new DefaultSavedRequest(request, new PortResolverImpl(), "continue"));
});
generatorByClassName.put(HttpSessionIdChangedEvent.class,
(r) -> new HttpSessionIdChangedEvent(new MockHttpSession(), "1"));
// webauthn
CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect(
CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_OPTIONAL,
true);
Bytes id = TestBytes.get();
AuthenticationExtensionsClientInputs inputs = new ImmutableAuthenticationExtensionsClientInputs(
ImmutableAuthenticationExtensionsClientInput.credProps);
// @formatter:off
PublicKeyCredentialDescriptor descriptor = PublicKeyCredentialDescriptor.builder()
.id(id)
.type(PublicKeyCredentialType.PUBLIC_KEY)
.transports(Set.of(AuthenticatorTransport.USB))
.build();
// @formatter:on
generatorByClassName.put(AuthenticatorTransport.class, (a) -> AuthenticatorTransport.USB);
generatorByClassName.put(PublicKeyCredentialType.class, (k) -> PublicKeyCredentialType.PUBLIC_KEY);
generatorByClassName.put(UserVerificationRequirement.class, (r) -> UserVerificationRequirement.REQUIRED);
generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.CredProtect.class, (c) -> credProtect);
generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.class,
(c) -> new CredProtectAuthenticationExtensionsClientInput(credProtect));
generatorByClassName.put(ImmutableAuthenticationExtensionsClientInputs.class, (i) -> inputs);
Field credPropsField = ReflectionUtils.findField(ImmutableAuthenticationExtensionsClientInput.class,
"credProps");
generatorByClassName.put(credPropsField.getType(),
(i) -> ImmutableAuthenticationExtensionsClientInput.credProps);
generatorByClassName.put(Bytes.class, (b) -> id);
generatorByClassName.put(PublicKeyCredentialDescriptor.class, (d) -> descriptor);
// @formatter:off
generatorByClassName.put(PublicKeyCredentialRequestOptions.class, (o) -> TestPublicKeyCredentialRequestOptions.create()
.extensions(inputs)
.allowCredentials(List.of(descriptor))
.build()
);
CredentialPropertiesOutput credentialOutput = new CredentialPropertiesOutput(false);
AuthenticationExtensionsClientOutputs outputs = new ImmutableAuthenticationExtensionsClientOutputs(credentialOutput);
AuthenticatorAssertionResponse response = TestAuthenticationAssertionResponses.createAuthenticatorAssertionResponse()
.build();
PublicKeyCredential<AuthenticatorAssertionResponse> credential = TestPublicKeyCredential.createPublicKeyCredential(
response, outputs)
.build();
RelyingPartyAuthenticationRequest authRequest = new RelyingPartyAuthenticationRequest(
TestPublicKeyCredentialRequestOptions.create().build(),
credential
);
WebAuthnAuthenticationRequestToken requestToken = new WebAuthnAuthenticationRequestToken(authRequest);
requestToken.setDetails(details);
generatorByClassName.put(CredentialPropertiesOutput.class, (o) -> credentialOutput);
generatorByClassName.put(ImmutableAuthenticationExtensionsClientOutputs.class, (o) -> outputs);
generatorByClassName.put(AuthenticatorAssertionResponse.class, (r) -> response);
generatorByClassName.put(RelyingPartyAuthenticationRequest.class, (r) -> authRequest);
generatorByClassName.put(PublicKeyCredential.class, (r) -> credential);
generatorByClassName.put(WebAuthnAuthenticationRequestToken.class, (r) -> requestToken);
generatorByClassName.put(AuthenticatorAttachment.class, (r) -> AuthenticatorAttachment.PLATFORM);
// @formatter:on
generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class,
(r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build());
generatorByClassName.put(WebAuthnAuthentication.class, (r) -> {
PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity()
.id(TestBytes.get())
.build();
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER");
WebAuthnAuthentication webAuthnAuthentication = new WebAuthnAuthentication(userEntity, authorities);
webAuthnAuthentication.setDetails(details);
return webAuthnAuthentication;
});
// @formatter:on
generatorByClassName.put(CredentialPropertiesOutput.ExtensionOutput.class,
(r) -> new CredentialPropertiesOutput(true).getOutput());
// One-Time Token
DefaultOneTimeToken oneTimeToken = new DefaultOneTimeToken(UUID.randomUUID().toString(), "user",
Instant.now().plusSeconds(300));
generatorByClassName.put(DefaultOneTimeToken.class, (t) -> oneTimeToken);
}
private SerializationSamples() {
}
static InstancioApi<?> instancioWithDefaults(Class<?> clazz) {
if (instancioByClassName.containsKey(clazz)) {
return instancioByClassName.get(clazz).get();
}
InstancioOfClassApi<?> instancio = Instancio.of(clazz);
ResolvableType[] generics = ResolvableType.forClass(clazz).getGenerics();
for (ResolvableType type : generics) {
instancio.withTypeParameters(type.resolve());
}
if (generatorByClassName.containsKey(clazz)) {
instancio.supply(Select.all(clazz), generatorByClassName.get(clazz));
}
return instancio;
}
private static <T extends AbstractAuthenticationToken> T applyDetails(T authentication) {
WebAuthenticationDetails details = new WebAuthenticationDetails("remote", "sessionId");
authentication.setDetails(details);
return authentication;
}
@SuppressWarnings("serial")
private static final class SerializableSupplier<T> implements Supplier<T>, Serializable {
private final T value;
SerializableSupplier(T value) {
this.value = value;
}
@Override
public T get() {
return this.value;
}
}
}
@@ -30,25 +30,12 @@ import java.lang.reflect.Modifier;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import jakarta.servlet.http.Cookie;
import org.apereo.cas.client.validation.AssertionImpl;
import org.instancio.Instancio;
import org.instancio.InstancioApi;
import org.instancio.InstancioOfClassApi;
import org.instancio.Select;
import org.instancio.generator.Generator;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -56,190 +43,8 @@ import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.ResolvableType;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.intercept.RunAsUserToken;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.ProviderNotFoundException;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent;
import org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent;
import org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent;
import org.springframework.security.authentication.event.AuthenticationFailureLockedEvent;
import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent;
import org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent;
import org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.authentication.event.LogoutSuccessEvent;
import org.springframework.security.authentication.jaas.JaasAuthenticationToken;
import org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent;
import org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent;
import org.springframework.security.authentication.ott.InvalidOneTimeTokenException;
import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken;
import org.springframework.security.authentication.password.CompromisedPasswordException;
import org.springframework.security.authorization.AuthorityAuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.context.TransientSecurityContext;
import org.springframework.security.core.session.AbstractSessionEvent;
import org.springframework.security.core.session.ReactiveSessionInformation;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.ldap.ppolicy.PasswordPolicyControl;
import org.springframework.security.ldap.ppolicy.PasswordPolicyErrorStatus;
import org.springframework.security.ldap.ppolicy.PasswordPolicyException;
import org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl;
import org.springframework.security.ldap.userdetails.LdapAuthority;
import org.springframework.security.oauth2.client.ClientAuthorizationException;
import org.springframework.security.oauth2.client.ClientAuthorizationRequiredException;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens;
import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens;
import org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken;
import org.springframework.security.oauth2.client.oidc.authentication.logout.TestOidcLogoutTokens;
import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation;
import org.springframework.security.oauth2.client.oidc.session.TestOidcSessionInformations;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
import org.springframework.security.oauth2.core.OAuth2DeviceCode;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.OAuth2UserCode;
import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipals;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
import org.springframework.security.oauth2.core.oidc.TestOidcIdTokens;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
import org.springframework.security.oauth2.core.oidc.user.TestOidcUsers;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import org.springframework.security.oauth2.core.user.TestOAuth2Users;
import org.springframework.security.oauth2.jwt.BadJwtException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoderInitializationException;
import org.springframework.security.oauth2.jwt.JwtEncodingException;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.oauth2.jwt.JwtValidationException;
import org.springframework.security.oauth2.jwt.TestJwts;
import org.springframework.security.oauth2.server.resource.BearerTokenError;
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
import org.springframework.security.saml2.Saml2Exception;
import org.springframework.security.saml2.core.Saml2Error;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal;
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationTokens;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2Authentications;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2PostAuthenticationRequests;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2RedirectAuthenticationRequests;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException;
import org.springframework.security.web.authentication.rememberme.CookieTheftException;
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.security.web.authentication.session.SessionFixationProtectionEvent;
import org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent;
import org.springframework.security.web.authentication.www.NonceExpiredException;
import org.springframework.security.web.csrf.CsrfException;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.csrf.InvalidCsrfTokenException;
import org.springframework.security.web.csrf.MissingCsrfTokenException;
import org.springframework.security.web.firewall.RequestRejectedException;
import org.springframework.security.web.savedrequest.DefaultSavedRequest;
import org.springframework.security.web.savedrequest.SimpleSavedRequest;
import org.springframework.security.web.server.firewall.ServerExchangeRejectedException;
import org.springframework.security.web.session.HttpSessionCreatedEvent;
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
import org.springframework.security.web.webauthn.api.Bytes;
import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput;
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInputs;
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs;
import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.PublicKeyCredential;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses;
import org.springframework.security.web.webauthn.api.TestBytes;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredential;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication;
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken;
import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
@@ -260,411 +65,12 @@ import static org.assertj.core.api.Assertions.fail;
*/
class SpringSecurityCoreVersionSerializableTests {
private static final Map<Class<?>, Generator<?>> generatorByClassName = new HashMap<>();
static final long securitySerialVersionUid = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
static Path currentVersionFolder = Paths.get("src/test/resources/serialized/" + getCurrentVersion());
static Path previousVersionFolder = Paths.get("src/test/resources/serialized/" + getPreviousVersion());
static {
UserDetails user = TestAuthentication.user();
Authentication authentication = TestAuthentication.authenticated(user);
SecurityContext securityContext = new SecurityContextImpl(authentication);
// oauth2-core
generatorByClassName.put(DefaultOAuth2User.class, (r) -> TestOAuth2Users.create());
generatorByClassName.put(OAuth2AuthorizationRequest.class,
(r) -> TestOAuth2AuthorizationRequests.request().build());
generatorByClassName.put(OAuth2AuthorizationResponse.class,
(r) -> TestOAuth2AuthorizationResponses.success().build());
generatorByClassName.put(OAuth2UserAuthority.class, (r) -> new OAuth2UserAuthority(Map.of("username", "user")));
generatorByClassName.put(OAuth2AuthorizationExchange.class, (r) -> TestOAuth2AuthorizationExchanges.success());
generatorByClassName.put(OidcUserInfo.class, (r) -> OidcUserInfo.builder().email("email@example.com").build());
generatorByClassName.put(SessionInformation.class,
(r) -> new SessionInformation(user, r.alphanumeric(4), new Date(1704378933936L)));
generatorByClassName.put(ReactiveSessionInformation.class,
(r) -> new ReactiveSessionInformation(user, r.alphanumeric(4), Instant.ofEpochMilli(1704378933936L)));
generatorByClassName.put(OAuth2AccessToken.class, (r) -> TestOAuth2AccessTokens.scopes("scope"));
generatorByClassName.put(OAuth2DeviceCode.class,
(r) -> new OAuth2DeviceCode("token", Instant.now(), Instant.now()));
generatorByClassName.put(OAuth2RefreshToken.class,
(r) -> new OAuth2RefreshToken("refreshToken", Instant.now(), Instant.now()));
generatorByClassName.put(OAuth2UserCode.class,
(r) -> new OAuth2UserCode("token", Instant.now(), Instant.now()));
generatorByClassName.put(DefaultOidcUser.class, (r) -> TestOidcUsers.create());
generatorByClassName.put(OidcUserAuthority.class,
(r) -> new OidcUserAuthority(TestOidcIdTokens.idToken().build(),
new OidcUserInfo(Map.of("claim", "value")), "claim"));
generatorByClassName.put(OAuth2AuthenticationException.class,
(r) -> new OAuth2AuthenticationException(new OAuth2Error("error", "description", "uri"), "message",
new RuntimeException()));
generatorByClassName.put(OAuth2AuthorizationException.class,
(r) -> new OAuth2AuthorizationException(new OAuth2Error("error", "description", "uri"), "message",
new RuntimeException()));
// oauth2-client
ClientRegistration.Builder clientRegistrationBuilder = TestClientRegistrations.clientRegistration();
ClientRegistration clientRegistration = clientRegistrationBuilder.build();
WebAuthenticationDetails details = new WebAuthenticationDetails("remote", "sessionId");
generatorByClassName.put(ClientRegistration.class, (r) -> clientRegistration);
generatorByClassName.put(ClientRegistration.ProviderDetails.class,
(r) -> clientRegistration.getProviderDetails());
generatorByClassName.put(ClientRegistration.ProviderDetails.UserInfoEndpoint.class,
(r) -> clientRegistration.getProviderDetails().getUserInfoEndpoint());
generatorByClassName.put(ClientRegistration.Builder.class, (r) -> clientRegistrationBuilder);
generatorByClassName.put(OAuth2AuthorizedClient.class,
(r) -> new OAuth2AuthorizedClient(clientRegistration, "principal", TestOAuth2AccessTokens.noScopes()));
generatorByClassName.put(OAuth2LoginAuthenticationToken.class, (r) -> {
var token = new OAuth2LoginAuthenticationToken(clientRegistration,
TestOAuth2AuthorizationExchanges.success());
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2AuthorizationCodeAuthenticationToken.class, (r) -> {
var token = TestOAuth2AuthorizationCodeAuthenticationTokens.authenticated();
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2AuthenticationToken.class, (r) -> {
var token = TestOAuth2AuthenticationTokens.authenticated();
token.setDetails(details);
return token;
});
generatorByClassName.put(OidcIdToken.class, (r) -> TestOidcIdTokens.idToken().build());
generatorByClassName.put(OidcLogoutToken.class,
(r) -> TestOidcLogoutTokens.withSessionId("issuer", "sessionId").issuedAt(Instant.now()).build());
generatorByClassName.put(OidcSessionInformation.class, (r) -> TestOidcSessionInformations.create());
generatorByClassName.put(DefaultOAuth2AuthenticatedPrincipal.class, (r) -> {
OAuth2AuthenticatedPrincipal principal = TestOAuth2AuthenticatedPrincipals.active();
return new DefaultOAuth2AuthenticatedPrincipal(principal.getName(), principal.getAttributes(),
(Collection<GrantedAuthority>) principal.getAuthorities());
});
generatorByClassName.put(ClientAuthorizationException.class,
(r) -> new ClientAuthorizationException(new OAuth2Error("error", "description", "uri"), "id", "message",
new RuntimeException()));
generatorByClassName.put(ClientAuthorizationRequiredException.class,
(r) -> new ClientAuthorizationRequiredException("id"));
// oauth2-jose
generatorByClassName.put(BadJwtException.class, (r) -> new BadJwtException("token", new RuntimeException()));
generatorByClassName.put(JwtDecoderInitializationException.class,
(r) -> new JwtDecoderInitializationException("message", new RuntimeException()));
generatorByClassName.put(JwtEncodingException.class,
(r) -> new JwtEncodingException("message", new RuntimeException()));
generatorByClassName.put(JwtException.class, (r) -> new JwtException("message", new RuntimeException()));
generatorByClassName.put(JwtValidationException.class,
(r) -> new JwtValidationException("message", List.of(new OAuth2Error("error", "description", "uri"))));
// oauth2-jwt
generatorByClassName.put(Jwt.class, (r) -> TestJwts.user());
// oauth2-resource-server
generatorByClassName
.put(org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken.class, (r) -> {
var token = new org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken(
"token");
token.setDetails(details);
return token;
});
generatorByClassName.put(BearerTokenAuthenticationToken.class, (r) -> {
var token = new BearerTokenAuthenticationToken("token");
token.setDetails(details);
return token;
});
generatorByClassName.put(BearerTokenAuthentication.class, (r) -> {
var token = new BearerTokenAuthentication(TestOAuth2AuthenticatedPrincipals.active(),
TestOAuth2AccessTokens.noScopes(), user.getAuthorities());
token.setDetails(details);
return token;
});
generatorByClassName.put(JwtAuthenticationToken.class, (r) -> {
var token = new JwtAuthenticationToken(TestJwts.user());
token.setDetails(details);
return token;
});
generatorByClassName.put(BearerTokenError.class, (r) -> BearerTokenErrors.invalidToken("invalid token"));
generatorByClassName.put(OAuth2IntrospectionAuthenticatedPrincipal.class,
(r) -> TestOAuth2AuthenticatedPrincipals.active());
generatorByClassName.put(InvalidBearerTokenException.class,
(r) -> new InvalidBearerTokenException("description", new RuntimeException()));
generatorByClassName.put(BadOpaqueTokenException.class,
(r) -> new BadOpaqueTokenException("message", new RuntimeException()));
generatorByClassName.put(OAuth2IntrospectionException.class,
(r) -> new OAuth2IntrospectionException("message", new RuntimeException()));
// core
generatorByClassName.put(RunAsUserToken.class, (r) -> {
RunAsUserToken token = new RunAsUserToken("key", user, "creds", user.getAuthorities(),
AnonymousAuthenticationToken.class);
token.setDetails(details);
return token;
});
generatorByClassName.put(RememberMeAuthenticationToken.class, (r) -> {
RememberMeAuthenticationToken token = new RememberMeAuthenticationToken("key", user, user.getAuthorities());
token.setDetails(details);
return token;
});
generatorByClassName.put(UsernamePasswordAuthenticationToken.class, (r) -> {
var token = UsernamePasswordAuthenticationToken.unauthenticated(user, "creds");
token.setDetails(details);
return token;
});
generatorByClassName.put(JaasAuthenticationToken.class, (r) -> {
var token = new JaasAuthenticationToken(user, "creds", null);
token.setDetails(details);
return token;
});
generatorByClassName.put(OneTimeTokenAuthenticationToken.class,
(r) -> applyDetails(new OneTimeTokenAuthenticationToken("username", "token")));
generatorByClassName.put(AccessDeniedException.class,
(r) -> new AccessDeniedException("access denied", new RuntimeException()));
generatorByClassName.put(AuthorizationServiceException.class,
(r) -> new AuthorizationServiceException("access denied", new RuntimeException()));
generatorByClassName.put(AccountExpiredException.class,
(r) -> new AccountExpiredException("error", new RuntimeException()));
generatorByClassName.put(AuthenticationCredentialsNotFoundException.class,
(r) -> new AuthenticationCredentialsNotFoundException("error", new RuntimeException()));
generatorByClassName.put(AuthenticationServiceException.class,
(r) -> new AuthenticationServiceException("error", new RuntimeException()));
generatorByClassName.put(BadCredentialsException.class,
(r) -> new BadCredentialsException("error", new RuntimeException()));
generatorByClassName.put(CredentialsExpiredException.class,
(r) -> new CredentialsExpiredException("error", new RuntimeException()));
generatorByClassName.put(DisabledException.class,
(r) -> new DisabledException("error", new RuntimeException()));
generatorByClassName.put(InsufficientAuthenticationException.class,
(r) -> new InsufficientAuthenticationException("error", new RuntimeException()));
generatorByClassName.put(InternalAuthenticationServiceException.class,
(r) -> new InternalAuthenticationServiceException("error", new RuntimeException()));
generatorByClassName.put(LockedException.class, (r) -> new LockedException("error", new RuntimeException()));
generatorByClassName.put(ProviderNotFoundException.class, (r) -> new ProviderNotFoundException("error"));
generatorByClassName.put(InvalidOneTimeTokenException.class, (r) -> new InvalidOneTimeTokenException("error"));
generatorByClassName.put(CompromisedPasswordException.class,
(r) -> new CompromisedPasswordException("error", new RuntimeException()));
generatorByClassName.put(UsernameNotFoundException.class,
(r) -> new UsernameNotFoundException("error", new RuntimeException()));
generatorByClassName.put(TestingAuthenticationToken.class,
(r) -> applyDetails(new TestingAuthenticationToken("username", "password")));
generatorByClassName.put(AuthenticationFailureBadCredentialsEvent.class,
(r) -> new AuthenticationFailureBadCredentialsEvent(authentication,
new BadCredentialsException("message")));
generatorByClassName.put(AuthenticationFailureCredentialsExpiredEvent.class,
(r) -> new AuthenticationFailureCredentialsExpiredEvent(authentication,
new CredentialsExpiredException("message")));
generatorByClassName.put(AuthenticationFailureDisabledEvent.class,
(r) -> new AuthenticationFailureDisabledEvent(authentication, new DisabledException("message")));
generatorByClassName.put(AuthenticationFailureExpiredEvent.class,
(r) -> new AuthenticationFailureExpiredEvent(authentication, new AccountExpiredException("message")));
generatorByClassName.put(AuthenticationFailureLockedEvent.class,
(r) -> new AuthenticationFailureLockedEvent(authentication, new LockedException("message")));
generatorByClassName.put(AuthenticationFailureProviderNotFoundEvent.class,
(r) -> new AuthenticationFailureProviderNotFoundEvent(authentication,
new ProviderNotFoundException("message")));
generatorByClassName.put(AuthenticationFailureProxyUntrustedEvent.class,
(r) -> new AuthenticationFailureProxyUntrustedEvent(authentication,
new AuthenticationServiceException("message")));
generatorByClassName.put(AuthenticationFailureServiceExceptionEvent.class,
(r) -> new AuthenticationFailureServiceExceptionEvent(authentication,
new AuthenticationServiceException("message")));
generatorByClassName.put(AuthenticationSuccessEvent.class,
(r) -> new AuthenticationSuccessEvent(authentication));
generatorByClassName.put(InteractiveAuthenticationSuccessEvent.class,
(r) -> new InteractiveAuthenticationSuccessEvent(authentication, Authentication.class));
generatorByClassName.put(LogoutSuccessEvent.class, (r) -> new LogoutSuccessEvent(authentication));
generatorByClassName.put(JaasAuthenticationFailedEvent.class,
(r) -> new JaasAuthenticationFailedEvent(authentication, new RuntimeException("message")));
generatorByClassName.put(JaasAuthenticationSuccessEvent.class,
(r) -> new JaasAuthenticationSuccessEvent(authentication));
generatorByClassName.put(AbstractSessionEvent.class, (r) -> new AbstractSessionEvent(securityContext));
generatorByClassName.put(SecurityConfig.class, (r) -> new SecurityConfig("value"));
generatorByClassName.put(TransientSecurityContext.class, (r) -> new TransientSecurityContext(authentication));
generatorByClassName.put(AuthorizationDeniedException.class,
(r) -> new AuthorizationDeniedException("message", new AuthorizationDecision(false)));
generatorByClassName.put(AuthorizationDecision.class, (r) -> new AuthorizationDecision(true));
generatorByClassName.put(AuthorityAuthorizationDecision.class,
(r) -> new AuthorityAuthorizationDecision(true, AuthorityUtils.createAuthorityList("ROLE_USER")));
// cas
generatorByClassName.put(CasServiceTicketAuthenticationToken.class, (r) -> {
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless("creds");
token.setDetails(details);
return token;
});
generatorByClassName.put(CasAuthenticationToken.class, (r) -> {
var token = new CasAuthenticationToken("key", user, "Password", user.getAuthorities(), user,
new AssertionImpl("test"));
token.setDetails(details);
return token;
});
generatorByClassName.put(CasAssertionAuthenticationToken.class, (r) -> {
var token = new CasAssertionAuthenticationToken(new AssertionImpl("test"), "ticket");
token.setDetails(details);
return token;
});
// ldap
generatorByClassName.put(LdapAuthority.class,
(r) -> new LdapAuthority("USER", "username", Map.of("attribute", List.of("value1", "value2"))));
generatorByClassName.put(PasswordPolicyException.class,
(r) -> new PasswordPolicyException(PasswordPolicyErrorStatus.INSUFFICIENT_PASSWORD_QUALITY));
generatorByClassName.put(PasswordPolicyControl.class, (r) -> new PasswordPolicyControl(true));
generatorByClassName.put(PasswordPolicyResponseControl.class, (r) -> {
byte[] encodedResponse = { 0x30, 0x05, (byte) 0xA0, 0x03, (byte) 0xA0, 0x1, 0x21 };
return new PasswordPolicyResponseControl(encodedResponse);
});
// saml2-service-provider
generatorByClassName.put(Saml2AuthenticationException.class,
(r) -> new Saml2AuthenticationException(new Saml2Error("code", "descirption"), "message",
new IOException("fail")));
generatorByClassName.put(Saml2Exception.class, (r) -> new Saml2Exception("message", new IOException("fail")));
generatorByClassName.put(DefaultSaml2AuthenticatedPrincipal.class,
(r) -> TestSaml2Authentications.authentication().getPrincipal());
generatorByClassName.put(Saml2Authentication.class,
(r) -> applyDetails(TestSaml2Authentications.authentication()));
generatorByClassName.put(Saml2PostAuthenticationRequest.class,
(r) -> TestSaml2PostAuthenticationRequests.create());
generatorByClassName.put(Saml2RedirectAuthenticationRequest.class,
(r) -> TestSaml2RedirectAuthenticationRequests.create());
generatorByClassName.put(Saml2X509Credential.class,
(r) -> TestSaml2X509Credentials.relyingPartyVerifyingCredential());
generatorByClassName.put(AssertingPartyDetails.class,
(r) -> TestRelyingPartyRegistrations.full().build().getAssertingPartyMetadata());
generatorByClassName.put(RelyingPartyRegistration.class, (r) -> TestRelyingPartyRegistrations.full().build());
generatorByClassName.put(Saml2AuthenticationToken.class, (r) -> {
Saml2AuthenticationToken token = TestSaml2AuthenticationTokens.tokenRequested();
token.setDetails(details);
return token;
});
// web
generatorByClassName.put(AnonymousAuthenticationToken.class, (r) -> {
Collection<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER");
return applyDetails(new AnonymousAuthenticationToken("key", "username", authorities));
});
generatorByClassName.put(PreAuthenticatedAuthenticationToken.class, (r) -> {
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(user, "creds",
user.getAuthorities());
token.setDetails(details);
return token;
});
generatorByClassName.put(PreAuthenticatedCredentialsNotFoundException.class,
(r) -> new PreAuthenticatedCredentialsNotFoundException("message", new IOException("fail")));
generatorByClassName.put(CookieTheftException.class, (r) -> new CookieTheftException("message"));
generatorByClassName.put(InvalidCookieException.class, (r) -> new InvalidCookieException("message"));
generatorByClassName.put(RememberMeAuthenticationException.class,
(r) -> new RememberMeAuthenticationException("message", new IOException("fail")));
generatorByClassName.put(SessionAuthenticationException.class,
(r) -> new SessionAuthenticationException("message"));
generatorByClassName.put(NonceExpiredException.class,
(r) -> new NonceExpiredException("message", new IOException("fail")));
generatorByClassName.put(CsrfException.class, (r) -> new CsrfException("message"));
generatorByClassName.put(org.springframework.security.web.server.csrf.CsrfException.class,
(r) -> new org.springframework.security.web.server.csrf.CsrfException("message"));
generatorByClassName.put(InvalidCsrfTokenException.class,
(r) -> new InvalidCsrfTokenException(new DefaultCsrfToken("header", "parameter", "token"), "token"));
generatorByClassName.put(MissingCsrfTokenException.class, (r) -> new MissingCsrfTokenException("token"));
generatorByClassName.put(DefaultCsrfToken.class, (r) -> new DefaultCsrfToken("header", "parameter", "token"));
generatorByClassName.put(org.springframework.security.web.server.csrf.DefaultCsrfToken.class,
(r) -> new org.springframework.security.web.server.csrf.DefaultCsrfToken("header", "parameter",
"token"));
generatorByClassName.put(RequestRejectedException.class, (r) -> new RequestRejectedException("message"));
generatorByClassName.put(ServerExchangeRejectedException.class,
(r) -> new ServerExchangeRejectedException("message"));
generatorByClassName.put(SessionFixationProtectionEvent.class,
(r) -> new SessionFixationProtectionEvent(authentication, "old", "new"));
generatorByClassName.put(AuthenticationSwitchUserEvent.class,
(r) -> new AuthenticationSwitchUserEvent(authentication, user));
generatorByClassName.put(HttpSessionCreatedEvent.class,
(r) -> new HttpSessionCreatedEvent(new MockHttpSession()));
generatorByClassName.put(SimpleSavedRequest.class, (r) -> {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/uri");
request.setQueryString("query=string");
request.setScheme("https");
request.setServerName("localhost");
request.setServerPort(80);
request.setRequestURI("/uri");
request.setCookies(new Cookie("name", "value"));
request.addHeader("header", "value");
request.addParameter("parameter", "value");
request.setPathInfo("/path");
request.addPreferredLocale(Locale.ENGLISH);
return new SimpleSavedRequest(new DefaultSavedRequest(request, new PortResolverImpl(), "continue"));
});
// webauthn
generatorByClassName.put(Bytes.class, (r) -> TestBytes.get());
generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class,
(r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build());
generatorByClassName.put(WebAuthnAuthentication.class, (r) -> {
PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity()
.id(TestBytes.get())
.build();
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER");
WebAuthnAuthentication webAuthnAuthentication = new WebAuthnAuthentication(userEntity, authorities);
webAuthnAuthentication.setDetails(details);
return webAuthnAuthentication;
});
// webauthn
CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect(
CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_OPTIONAL,
true);
Bytes id = TestBytes.get();
AuthenticationExtensionsClientInputs inputs = new ImmutableAuthenticationExtensionsClientInputs(
ImmutableAuthenticationExtensionsClientInput.credProps);
// @formatter:off
PublicKeyCredentialDescriptor descriptor = PublicKeyCredentialDescriptor.builder()
.id(id)
.type(PublicKeyCredentialType.PUBLIC_KEY)
.transports(Set.of(AuthenticatorTransport.USB))
.build();
// @formatter:on
generatorByClassName.put(AuthenticatorTransport.class, (a) -> AuthenticatorTransport.USB);
generatorByClassName.put(PublicKeyCredentialType.class, (k) -> PublicKeyCredentialType.PUBLIC_KEY);
generatorByClassName.put(UserVerificationRequirement.class, (r) -> UserVerificationRequirement.REQUIRED);
generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.CredProtect.class, (c) -> credProtect);
generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.class,
(c) -> new CredProtectAuthenticationExtensionsClientInput(credProtect));
generatorByClassName.put(ImmutableAuthenticationExtensionsClientInputs.class, (i) -> inputs);
Field credPropsField = ReflectionUtils.findField(ImmutableAuthenticationExtensionsClientInput.class,
"credProps");
generatorByClassName.put(credPropsField.getType(),
(i) -> ImmutableAuthenticationExtensionsClientInput.credProps);
generatorByClassName.put(Bytes.class, (b) -> id);
generatorByClassName.put(PublicKeyCredentialDescriptor.class, (d) -> descriptor);
// @formatter:off
generatorByClassName.put(PublicKeyCredentialRequestOptions.class, (o) -> TestPublicKeyCredentialRequestOptions.create()
.extensions(inputs)
.allowCredentials(List.of(descriptor))
.build()
);
CredentialPropertiesOutput credentialOutput = new CredentialPropertiesOutput(false);
AuthenticationExtensionsClientOutputs outputs = new ImmutableAuthenticationExtensionsClientOutputs(credentialOutput);
AuthenticatorAssertionResponse response = TestAuthenticationAssertionResponses.createAuthenticatorAssertionResponse()
.build();
PublicKeyCredential<AuthenticatorAssertionResponse> credential = TestPublicKeyCredential.createPublicKeyCredential(
response, outputs)
.build();
RelyingPartyAuthenticationRequest authRequest = new RelyingPartyAuthenticationRequest(
TestPublicKeyCredentialRequestOptions.create().build(),
credential
);
WebAuthnAuthenticationRequestToken requestToken = new WebAuthnAuthenticationRequestToken(authRequest);
requestToken.setDetails(details);
generatorByClassName.put(CredentialPropertiesOutput.class, (o) -> credentialOutput);
generatorByClassName.put(ImmutableAuthenticationExtensionsClientOutputs.class, (o) -> outputs);
generatorByClassName.put(AuthenticatorAssertionResponse.class, (r) -> response);
generatorByClassName.put(RelyingPartyAuthenticationRequest.class, (r) -> authRequest);
generatorByClassName.put(PublicKeyCredential.class, (r) -> credential);
generatorByClassName.put(WebAuthnAuthenticationRequestToken.class, (r) -> requestToken);
generatorByClassName.put(AuthenticatorAttachment.class, (r) -> AuthenticatorAttachment.PLATFORM);
// @formatter:on
}
@ParameterizedTest
@MethodSource("getClassesToSerialize")
@Disabled("This method should only be used to serialize the classes once")
@@ -676,7 +82,7 @@ class SpringSecurityCoreVersionSerializableTests {
return;
}
Files.createFile(filePath);
Object instance = instancioWithDefaults(clazz).create();
Object instance = SerializationSamples.instancioWithDefaults(clazz).create();
assertThat(instance).isInstanceOf(clazz);
try (FileOutputStream fileOutputStream = new FileOutputStream(file);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) {
@@ -690,7 +96,28 @@ class SpringSecurityCoreVersionSerializableTests {
}
@ParameterizedTest
@MethodSource("getFilesToDeserialize")
@MethodSource("getCurrentSerializedFiles")
void shouldBeAbleToDeserializeClassFromCurrentVersion(Path filePath) {
try (FileInputStream fileInputStream = new FileInputStream(filePath.toFile());
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) {
Object obj = objectInputStream.readObject();
Class<?> clazz = Class.forName(filePath.getFileName().toString().replace(".serialized", ""));
assertThat(obj).isInstanceOf(clazz);
}
catch (IOException | ClassNotFoundException ex) {
fail("Could not deserialize " + filePath, ex);
}
}
static Stream<Path> getCurrentSerializedFiles() throws Exception {
assertThat(currentVersionFolder.toFile().exists())
.as("Make sure that the " + currentVersionFolder + " exists and is not empty")
.isTrue();
return getClassesToSerialize().map((clazz) -> currentVersionFolder.resolve(clazz.getName() + ".serialized"));
}
@ParameterizedTest
@MethodSource("getPreviousSerializedFiles")
void shouldBeAbleToDeserializeClassFromPreviousVersion(Path filePath) {
try (FileInputStream fileInputStream = new FileInputStream(filePath.toFile());
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) {
@@ -703,7 +130,7 @@ class SpringSecurityCoreVersionSerializableTests {
}
}
static Stream<Path> getFilesToDeserialize() throws IOException {
static Stream<Path> getPreviousSerializedFiles() throws IOException {
assertThat(previousVersionFolder.toFile().exists())
.as("Make sure that the " + previousVersionFolder + " exists and is not empty")
.isTrue();
@@ -739,10 +166,18 @@ class SpringSecurityCoreVersionSerializableTests {
|| Arrays.asList(suppressWarnings.value()).contains("Serial");
if (!hasSerialVersion && !hasSerialIgnore) {
classes.add(clazz);
continue;
}
boolean isReachable = Modifier.isPublic(clazz.getModifiers());
boolean hasSampleSerialization = currentVersionFolder.resolve(clazz.getName() + ".serialized")
.toFile()
.exists();
if (hasSerialVersion && isReachable && !hasSampleSerialization) {
classes.add(clazz);
}
}
assertThat(classes)
.describedAs("Found Serializable classes that are either missing a serialVersionUID or a @SuppressWarnings")
assertThat(classes).describedAs(
"Found Serializable classes that are either missing a serialVersionUID or a @SuppressWarnings or a sample serialized file")
.isEmpty();
}
@@ -760,7 +195,7 @@ class SpringSecurityCoreVersionSerializableTests {
}
boolean matchesExpectedSerialVersion = ObjectStreamClass.lookup(clazz)
.getSerialVersionUID() == securitySerialVersionUid;
boolean isUnderTest = generatorByClassName.containsKey(clazz);
boolean isUnderTest = SerializationSamples.generatorByClassName.containsKey(clazz);
if (matchesExpectedSerialVersion || isUnderTest) {
classes.add(clazz);
}
@@ -768,24 +203,6 @@ class SpringSecurityCoreVersionSerializableTests {
return classes.stream();
}
private static InstancioApi<?> instancioWithDefaults(Class<?> clazz) {
InstancioOfClassApi<?> instancio = Instancio.of(clazz);
ResolvableType[] generics = ResolvableType.forClass(clazz).getGenerics();
for (ResolvableType type : generics) {
instancio.withTypeParameters(type.resolve());
}
if (generatorByClassName.containsKey(clazz)) {
instancio.supply(Select.all(clazz), generatorByClassName.get(clazz));
}
return instancio;
}
private static <T extends AbstractAuthenticationToken> T applyDetails(T authentication) {
WebAuthenticationDetails details = new WebAuthenticationDetails("remote", "sessionId");
authentication.setDetails(details);
return authentication;
}
private static String getCurrentVersion() {
String version = System.getProperty("springSecurityVersion");
String[] parts = version.split("\\.");
@@ -55,6 +55,7 @@ public class Authz {
return Mono.just(checkResult(result));
}
@SuppressWarnings("serial")
public static class AuthzResult extends AuthorizationDecision {
public AuthzResult(boolean granted) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@@ -214,7 +214,7 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
private static Method findMethod(Method method, Class<?> targetClass) {
for (Method candidate : targetClass.getDeclaredMethods()) {
if (candidate == method) {
if (candidate.equals(method)) {
return candidate;
}
if (isOverride(method, candidate)) {
@@ -16,18 +16,15 @@
package org.springframework.security.access.annotation;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
/**
* @author Joe Scalise
*/
@SuppressWarnings("serial")
public class BusinessServiceImpl<E extends Entity> implements BusinessService {
@Serial
private static final long serialVersionUID = -4249394090237180795L;
@Override
@Secured({ "ROLE_USER" })
public void someUserMethod1() {
@@ -16,7 +16,6 @@
package org.springframework.security.access.annotation;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
@@ -24,11 +23,9 @@ import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
@SuppressWarnings("serial")
public class ExpressionProtectedBusinessServiceImpl implements BusinessService {
@Serial
private static final long serialVersionUID = -3320014879907436606L;
@Override
public void someAdminMethod() {
}
@@ -16,7 +16,6 @@
package org.springframework.security.access.annotation;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
@@ -27,11 +26,9 @@ import jakarta.annotation.security.RolesAllowed;
* @author Luke Taylor
*/
@PermitAll
@SuppressWarnings("serial")
public class Jsr250BusinessServiceImpl implements BusinessService {
@Serial
private static final long serialVersionUID = -7550211450382764339L;
@Override
@RolesAllowed("ROLE_USER")
public void someUserMethod1() {
@@ -111,7 +111,7 @@ final class Argon2EncodingUtils {
case "argon2d" -> new Argon2Parameters.Builder(Argon2Parameters.ARGON2_d);
case "argon2i" -> new Argon2Parameters.Builder(Argon2Parameters.ARGON2_i);
case "argon2id" -> new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id);
default -> throw new IllegalArgumentException("Invalid algorithm type: " + parts[0]);
default -> throw new IllegalArgumentException("Invalid algorithm type: " + parts[1]);
};
if (parts[currentPart].startsWith("v=")) {
paramsBuilder.withVersion(Integer.parseInt(parts[currentPart].substring(2)));
@@ -94,8 +94,10 @@ public class Argon2EncodingUtilsTests {
@Test
public void decodeWhenNonexistingAlgorithmThenThrowException() {
assertThatIllegalArgumentException().isThrownBy(() -> Argon2EncodingUtils
.decode("$argon2x$v=19$m=1024,t=3,p=2$Y1JkRmJDdzIzZ3oyTWx4aw$cGE5Cbd/cx7micVhXVBdH5qTr66JI1iUyuNNVAnErXs"));
assertThatIllegalArgumentException()
.isThrownBy(() -> Argon2EncodingUtils.decode(
"$argon2x$v=19$m=1024,t=3,p=2$Y1JkRmJDdzIzZ3oyTWx4aw$cGE5Cbd/cx7micVhXVBdH5qTr66JI1iUyuNNVAnErXs"))
.withMessageContaining("argon2x");
}
@Test
+1
View File
@@ -86,6 +86,7 @@
**** xref:servlet/saml2/login/authentication.adoc[SAML2 Authentication Responses]
*** xref:servlet/saml2/logout.adoc[SAML2 Logout]
*** xref:servlet/saml2/metadata.adoc[SAML2 Metadata]
*** xref:servlet/saml2/saml-extension-migration.adoc[Migrating from Spring Security SAML Extension]
** xref:servlet/exploits/index.adoc[Protection Against Exploits]
*** xref:servlet/exploits/csrf.adoc[]
*** xref:servlet/exploits/headers.adoc[]
@@ -29,7 +29,7 @@ spring:
security:
oauth2:
resourceserver:
opaque-token:
opaquetoken:
introspection-uri: https://idp.example.com/introspect
client-id: client
client-secret: secret
@@ -616,7 +616,7 @@ spring:
security:
oauth2:
resourceserver:
opaque-token:
opaquetoken:
introspection-uri: https://idp.example.org/introspection
client-id: client
client-secret: secret
@@ -259,7 +259,7 @@ Java::
+
[source,java,role="primary"]
----
HeaderWriterLogoutHandler clearSiteData = new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter());
HeaderWriterLogoutHandler clearSiteData = new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(Directives.ALL));
http
.logout((logout) -> logout.addLogoutHandler(clearSiteData))
----
@@ -268,7 +268,7 @@ Kotlin::
+
[source,kotlin,role="secondary"]
----
val clearSiteData = HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter())
val clearSiteData = HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(Directives.ALL))
http {
logout {
addLogoutHandler(clearSiteData)
@@ -402,7 +402,7 @@ SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();
@PostMapping("/my/logout")
public String performLogout(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
// .. perform logout
this.logoutHandler.doLogout(request, response, authentication);
this.logoutHandler.logout(request, response, authentication);
return "redirect:/home";
}
----
@@ -416,7 +416,7 @@ val logoutHandler = SecurityContextLogoutHandler()
@PostMapping("/my/logout")
fun performLogout(val authentication: Authentication, val request: HttpServletRequest, val response: HttpServletResponse): String {
// .. perform logout
this.logoutHandler.doLogout(request, response, authentication)
this.logoutHandler.logout(request, response, authentication)
return "redirect:/home"
}
----
@@ -534,6 +534,13 @@ public class MaximumSessionsPreventLoginTests {
If you are using a customized authentication filter for form-based login, then you have to configure concurrent session control support explicitly.
You can try it using the {gh-samples-url}/servlet/spring-boot/java/session-management/maximum-sessions-prevent-login[Maximum Sessions Prevent Login sample].
[NOTE]
=====
If you are using a custom implementation of `UserDetails`, ensure you override the **equals()** and **hashCode()** methods.
The default `SessionRegistry` implementation in Spring Security relies on an in-memory Map that uses these methods to correctly identify and manage user sessions.
Failing to override them may lead to issues where session tracking and user comparison behave unexpectedly.
=====
== Detecting Timeouts
Sessions expire on their own, and there is nothing that needs to be done to ensure that a security context gets removed.
@@ -8,14 +8,12 @@ The browser automatically checks that the certificate presented by a server has
You can also use SSL with "`mutual authentication`". The server then requests a valid certificate from the client as part of the SSL handshake.
The server authenticates the client by checking that its certificate is signed by an acceptable authority.
If a valid certificate has been provided, it can be obtained through the servlet API in an application.
The Spring Security X.509 module extracts the certificate by using a filter.
It maps the certificate to an application user and loads that user's set of granted authorities for use with the standard Spring Security infrastructure.
You can also use SSL with "`mutual authentication`". The server then requests a valid certificate from the client as part of the SSL handshake.
The server authenticates the client by checking that its certificate is signed by an acceptable authority.
For example, if you use Tomcat, you should read the https://tomcat.apache.org/tomcat-10.1-doc/ssl-howto.html[Tomcat SSL instructions].
You should get this working before trying it out with Spring Security.
The Spring Security X.509 module extracts the certificate by using a filter.
It maps the certificate to an application user and loads that user's set of granted authorities for use with the standard Spring Security infrastructure.
== Adding X.509 Authentication to Your Web Application
Enabling X.509 client authentication is very straightforward.
@@ -28,7 +28,7 @@ spring:
security:
oauth2:
resourceserver:
opaque-token:
opaquetoken:
introspection-uri: https://idp.example.com/introspect
client-id: client
client-secret: secret
@@ -786,7 +786,7 @@ spring:
security:
oauth2:
resourceserver:
opaque-token:
opaquetoken:
introspection-uri: https://idp.example.org/introspection
client-id: client
client-secret: secret
@@ -103,10 +103,11 @@ spring:
security:
saml2:
relyingparty:
okta:
identityprovider:
entity-id: ...
singlesignon.sign-request: false
registration:
okta:
assertingparty:
entity-id: ...
singlesignon.sign-request: false
----
Java::
@@ -125,7 +125,7 @@ spring:
relyingparty:
registration:
adfs:
identityprovider:
assertingparty:
entity-id: https://idp.example.com/issuer
verification.credentials:
- certificate-location: "classpath:idp.crt"
@@ -886,16 +886,17 @@ spring:
security:
saml2:
relyingparty:
okta:
signing.credentials: &relying-party-credentials
- private-key-location: classpath:rp.key
certificate-location: classpath:rp.crt
identityprovider:
entity-id: ...
azure:
signing.credentials: *relying-party-credentials
identityprovider:
entity-id: ...
registration:
okta:
signing.credentials: &relying-party-credentials
- private-key-location: classpath:rp.key
certificate-location: classpath:rp.crt
assertingparty:
entity-id: ...
azure:
signing.credentials: *relying-party-credentials
assertingparty:
entity-id: ...
----
Second, in a database, you need not replicate the model of `RelyingPartyRegistration`.
@@ -0,0 +1,67 @@
= SAML 2.0 Extension Migration
This document contains guidance for moving SAML 2.0 Service Providers from Spring Security SAML Extensions 1.x to Spring Security Since Spring Security doesnt provide Identity Provider support, migrating a Spring Security SAML Extensions Identity Provider is out of scope for this document.
Because the two approaches are as different as they are, this document will tend to cover patterns more than precise search-and-replace steps.
[[saml2-login-logout]]
== Login & Logout
=== Changes In Approach
https://github.com/spring-projects/spring-security[Spring Security] takes a slightly different approach from https://github.com/spring-projects/spring-security-saml[Spring Security SAML Extensions] in a few notable ways.
==== Simplified Enablement
Spring Security SAML Extensions support for Service Providers is provided by a series of filters enabled by adding each filter manually in the correct order to various Spring Security filter chains.
Spring Securitys SAML 2.0 Service Provider support is enabled via the Spring Security DSL methods:
xref:servlet/saml2/login/index.adoc[`saml2Login`],
xref:servlet/saml2/logout.adoc[`saml2Logout`], and
xref:servlet/saml2/metadata.adoc[`saml2Metadata`]. It selects the correct filters to add and puts them in the appropriate places in the filter chain.
==== Stronger Encapsulation
Like Spring Security SAML Extensions, Spring Security bases its SAML support on OpenSAML. The Extensions project exposes OpenSAML over public interfaces, blurring the lines between the two projects, effectively requiring OpenSAML, and making upgrades to later versions of OpenSAML more complicated.
Spring Security provides stronger encapsulation. No public interfaces expose OpenSAML components and any class that exposes OpenSAML in its public API is named with an `OpenSaml` prefix for additional clarity.
==== Out-of-the-box Multitenancy
Spring Security SAML Extensions offered some lightweight support for declaring more than one Identity Provider and accessing it at login time using the `idp` request parameter. This was limiting as far as changing things at runtime was concerned and also doesnt allow for a many-to-many relationship between relying and asserting parties.
Spring Security builds SAML 2.0 multitenancy into its default URLs and basic components in the form of a `RelyingPartyRegistration`. This component acts as a link between a Relying Partys metadata and an Asserting Partys metadata, and all pairs are available for lookup in a `RelyingPartyRegistrationRepository`. Each URL represents a unique registration pair to be retrieved.
Whether its AuthnRequests, Responses, LogoutRequests, LogoutResponses, or EntityDescriptors, each filter is based off of `RelyingPartyRegistrationRepository` and so is fundamentally multi-tenant.
=== Examples Matrix
Both Spring Security and Spring Security SAML Extensions have examples for how to configure the Service Provider:
[options="header"]
|===
| Use case | Spring Security | Spring Security SAML Extension
| Login & Logout | https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/saml2/login[Sample] |
https://github.com/jzheaux/spring-security-saml-migrate/tree/main/login-logout[Sample]
| Login using SAML Extension URLs | https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/saml2/custom-urls[Sample] | -
| Metadata support | https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/saml2/refreshable-metadata[Sample] | -
|===
You can also see a showcase example in https://github.com/spring-projects/spring-security-saml/tree/main/sample[Spring Security SAML Extension]'s GitHub project.
[NOTE]
====
Spring Security does not support HTTP-Redirect binding for SAML 2.0 Responses.
According to the SAML specification, the HTTP-Redirect binding is not permitted for SAML Responses due to URL length and signature limitations. Attempting to use this binding may result in unexpected errors.
Use HTTP-POST binding instead when configuring your identity provider.
====
[[saml2-unported]]
== Unported Features
There are some features that are not yet ported over and there are as yet no plans to do so:
* HTTP-Redirect binding for SAML 2.0 Responses
* Artifact binding support
+1 -1
View File
@@ -14,7 +14,7 @@
# limitations under the License.
#
springBootVersion=3.3.3
version=6.4.5
version=6.4.7
samplesBranch=main
org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError
org.gradle.parallel=true
+10 -10
View File
@@ -1,11 +1,11 @@
[versions]
com-squareup-okhttp3 = "3.14.9"
io-rsocket = "1.1.5"
io-spring-javaformat = "0.0.43"
io-spring-javaformat = "0.0.46"
io-spring-nohttp = "0.0.11"
jakarta-websocket = "2.2.0"
org-apache-directory-server = "1.5.5"
org-apache-maven-resolver = "1.9.22"
org-apache-maven-resolver = "1.9.23"
org-aspectj = "1.9.24"
org-bouncycastle = "1.79"
org-eclipse-jetty = "11.0.25"
@@ -14,11 +14,11 @@ org-jetbrains-kotlinx = "1.9.0"
org-mockito = "5.14.2"
org-opensaml = "4.3.2"
org-opensaml5 = "5.1.2"
org-springframework = "6.2.6"
org-springframework = "6.2.7"
[libraries]
ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18"
com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.3"
com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.4.1"
com-google-inject-guice = "com.google.inject:guice:3.0"
com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0"
com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3"
@@ -28,15 +28,15 @@ com-squareup-okhttp3-okhttp = { module = "com.squareup.okhttp3:okhttp", version.
com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11"
com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1"
commons-collections = "commons-collections:commons-collections:3.2.2"
io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6"
io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8"
io-mockk = "io.mockk:mockk:1.13.17"
io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.17"
io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.19"
io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" }
io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" }
io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" }
io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" }
io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" }
io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.4"
io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.6"
jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1"
jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1"
jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0"
@@ -56,7 +56,7 @@ org-apache-directory-server-apacheds-protocol-shared = { module = "org.apache.di
org-apache-directory-server-apacheds-server-jndi = { module = "org.apache.directory.server:apacheds-server-jndi", version.ref = "org-apache-directory-server" }
org-apache-directory-shared-shared-ldap = "org.apache.directory.shared:shared-ldap:0.9.15"
org-apache-httpcomponents-httpclient = "org.apache.httpcomponents:httpclient:4.5.14"
org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.9"
org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.10"
org-apache-maven-resolver-maven-resolver-connector-basic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "org-apache-maven-resolver" }
org-apache-maven-resolver-maven-resolver-impl = { module = "org.apache.maven.resolver:maven-resolver-impl", version.ref = "org-apache-maven-resolver" }
org-apache-maven-resolver-maven-resolver-transport-http = { module = "org.apache.maven.resolver:maven-resolver-transport-http", version.ref = "org-apache-maven-resolver" }
@@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on",
org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" }
org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" }
org-hamcrest = "org.hamcrest:hamcrest:2.2"
org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.13.Final"
org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final"
org-hsqldb = "org.hsqldb:hsqldb:2.7.4"
org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" }
org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25"
@@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup
org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3"
org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36"
org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17"
org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.4"
org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6"
org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12"
org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" }
org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0"
Binary file not shown.
+2 -2
View File
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
distributionSha256Sum=61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+2 -2
View File
@@ -114,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
Vendored
+2 -2
View File
@@ -70,11 +70,11 @@ goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.springframework.security.oauth2.client.registration;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -49,6 +50,7 @@ import org.springframework.web.util.UriComponentsBuilder;
* @author Rob Winch
* @author Josh Cummings
* @author Rafiullah Hamedy
* @author Evgeniy Cheban
* @since 5.1
*/
public final class ClientRegistrations {
@@ -251,6 +253,7 @@ public final class ClientRegistrations {
private static ClientRegistration.Builder getBuilder(String issuer,
Supplier<ClientRegistration.Builder>... suppliers) {
String errorMessage = "Unable to resolve Configuration with the provided Issuer of \"" + issuer + "\"";
List<String> errors = new ArrayList<>();
for (Supplier<ClientRegistration.Builder> supplier : suppliers) {
try {
return supplier.get();
@@ -259,6 +262,7 @@ public final class ClientRegistrations {
if (!ex.getStatusCode().is4xxClientError()) {
throw ex;
}
errors.add(ex.getMessage());
// else try another endpoint
}
catch (IllegalArgumentException | IllegalStateException ex) {
@@ -268,6 +272,9 @@ public final class ClientRegistrations {
throw new IllegalArgumentException(errorMessage, ex);
}
}
if (!errors.isEmpty()) {
throw new IllegalArgumentException(errorMessage + ", errors: " + errors);
}
throw new IllegalArgumentException(errorMessage);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,12 +36,14 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* @author Rob Winch
* @author Rafiullah Hamedy
* @author Evgeniy Cheban
* @since 5.1
*/
public class ClientRegistrationsTests {
@@ -569,6 +571,27 @@ public class ClientRegistrationsTests {
.isEqualTo(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
}
@Test
public void issuerWhenAllEndpointsFailedThenExceptionIncludesFailureInformation() {
this.issuer = createIssuerFromServer("issuer1");
this.server.setDispatcher(new Dispatcher() {
@Override
public MockResponse dispatch(RecordedRequest request) {
int responseCode = switch (request.getPath()) {
case "/issuer1/.well-known/openid-configuration" -> 405;
case "/.well-known/openid-configuration/issuer1" -> 400;
default -> 404;
};
return new MockResponse().setResponseCode(responseCode);
}
});
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> ClientRegistrations.fromIssuerLocation(this.issuer).build())
.withMessageContaining("405")
.withMessageContaining("400")
.withMessageContaining("404");
}
private ClientRegistration.Builder registration(String path) throws Exception {
this.issuer = createIssuerFromServer(path);
this.response.put("issuer", this.issuer);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@@ -160,7 +160,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider {
String inResponseTo = response.getInResponseTo();
result = result.concat(validateInResponseTo(token.getAuthenticationRequest(), inResponseTo));
String issuer = response.getIssuer().getValue();
String issuer = issuer(response);
String destination = response.getDestination();
String location = token.getRelyingPartyRegistration().getAssertionConsumerServiceLocation();
if (StringUtils.hasText(destination) && !destination.equals(location)) {
@@ -183,6 +183,13 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider {
};
}
private static String issuer(Response response) {
if (response.getIssuer() == null) {
return null;
}
return response.getIssuer().getValue();
}
private static List<String> getStatusCodes(Response response) {
if (response.getStatus() == null) {
return List.of(StatusCode.SUCCESS);
@@ -308,7 +315,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider {
}
private void process(Saml2AuthenticationToken token, Response response) {
String issuer = response.getIssuer().getValue();
String issuer = issuer(response);
this.logger.debug(LogMessage.format("Processing SAML response from %s", issuer));
boolean responseSigned = response.isSigned();
@@ -889,6 +889,15 @@ public class OpenSaml4AuthenticationProviderTests {
provider.authenticate(token);
}
// gh-16989
@Test
public void authenticateWhenNullIssuerThenNoNullPointer() {
OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider();
Response response = TestOpenSamlObjects.signedResponseWithOneAssertion((r) -> r.setIssuer(null));
Saml2AuthenticationToken token = token(response, verifying(registration()));
assertThatExceptionOfType(Saml2AuthenticationException.class).isThrownBy(() -> provider.authenticate(token));
}
private <T extends XMLObject> T build(QName qName) {
return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName);
}
@@ -889,6 +889,15 @@ public class OpenSaml5AuthenticationProviderTests {
provider.authenticate(token);
}
// gh-16989
@Test
public void authenticateWhenNullIssuerThenNoNullPointer() {
OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider();
Response response = TestOpenSamlObjects.signedResponseWithOneAssertion((r) -> r.setIssuer(null));
Saml2AuthenticationToken token = token(response, verifying(registration()));
assertThatExceptionOfType(Saml2AuthenticationException.class).isThrownBy(() -> provider.authenticate(token));
}
private <T extends XMLObject> T build(QName qName) {
return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName);
}
+1 -1
View File
@@ -5,7 +5,7 @@ pluginManagement {
}
plugins {
id "io.spring.develocity.conventions" version "0.0.22"
id "io.spring.develocity.conventions" version "0.0.23"
}
dependencyResolutionManagement {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2025 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.
@@ -64,6 +64,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
* </ul>
*
* @author Sergey Bespalov
* @author Andrey Litvitski
* @since 5.2.0
*/
public class AuthenticationFilter extends OncePerRequestFilter {
@@ -193,6 +194,15 @@ public class AuthenticationFilter extends OncePerRequestFilter {
}
}
@Override
protected String getAlreadyFilteredAttributeName() {
String name = getFilterName();
if (name == null) {
name = getClass().getName().concat("-" + System.identityHashCode(this));
}
return name + ALREADY_FILTERED_SUFFIX;
}
private void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException failed) throws IOException, ServletException {
this.securityContextHolderStrategy.clearContext();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2025 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.
@@ -79,6 +79,10 @@ import org.springframework.web.filter.GenericFilterBean;
* raised by the <tt>AuthenticationManager</tt> will the be re-thrown. Note that this will
* not affect cases where the principal returned by {@link #getPreAuthenticatedPrincipal}
* is null, when the chain will still proceed as normal.
* <p>
* The filter saves the {@link SecurityContext} using the configured
* {@link SecurityContextRepository}, which can be set via
* {@link #setSecurityContextRepository}.
*
* @author Luke Taylor
* @author Ruud Senden
@@ -253,8 +257,8 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
/**
* Sets the {@link SecurityContextRepository} to save the {@link SecurityContext} on
* authentication success. The default action is not to save the
* {@link SecurityContext}.
* authentication success. The default action is to save the {@link SecurityContext}
* in {@link HttpSession} using {@link HttpSessionSecurityContextRepository}.
* @param securityContextRepository the {@link SecurityContextRepository} to use.
* Cannot be null.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2025 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.
@@ -75,6 +75,7 @@ public final class ClearSiteDataHeaderWriter implements HeaderWriter {
if (!response.containsHeader(CLEAR_SITE_DATA_HEADER)) {
response.setHeader(CLEAR_SITE_DATA_HEADER, this.headerValue);
}
return;
}
this.logger.debug(
LogMessage.format("Not injecting Clear-Site-Data header since it did not match the requestMatcher %s",
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@@ -802,42 +802,42 @@ public class StrictServerWebExchangeFirewall implements ServerWebExchangeFirewal
@Override
public Builder method(HttpMethod httpMethod) {
return this.delegate.method(httpMethod);
return new StrictFirewallBuilder(this.delegate.method(httpMethod));
}
@Override
public Builder uri(URI uri) {
return this.delegate.uri(uri);
return new StrictFirewallBuilder(this.delegate.uri(uri));
}
@Override
public Builder path(String path) {
return this.delegate.path(path);
return new StrictFirewallBuilder(this.delegate.path(path));
}
@Override
public Builder contextPath(String contextPath) {
return this.delegate.contextPath(contextPath);
return new StrictFirewallBuilder(this.delegate.contextPath(contextPath));
}
@Override
public Builder header(String headerName, String... headerValues) {
return this.delegate.header(headerName, headerValues);
return new StrictFirewallBuilder(this.delegate.header(headerName, headerValues));
}
@Override
public Builder headers(Consumer<HttpHeaders> headersConsumer) {
return this.delegate.headers(headersConsumer);
return new StrictFirewallBuilder(this.delegate.headers(headersConsumer));
}
@Override
public Builder sslInfo(SslInfo sslInfo) {
return this.delegate.sslInfo(sslInfo);
return new StrictFirewallBuilder(this.delegate.sslInfo(sslInfo));
}
@Override
public Builder remoteAddress(InetSocketAddress remoteAddress) {
return this.delegate.remoteAddress(remoteAddress);
return new StrictFirewallBuilder(this.delegate.remoteAddress(remoteAddress));
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.springframework.security.web.authentication;
import jakarta.servlet.FilterChain;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
@@ -57,6 +58,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* @author Sergey Bespalov
* @author Andrey Litvitski
* @since 5.2.0
*/
@ExtendWith(MockitoExtension.class)
@@ -318,4 +320,18 @@ public class AuthenticationFilterTests {
assertThat(securityContextArg.getValue().getAuthentication()).isEqualTo(authentication);
}
@Test
public void filterWhenMultipleInChainThenAllFiltered() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
MockHttpServletResponse response = new MockHttpServletResponse();
AuthenticationFilter filter1 = new AuthenticationFilter(this.authenticationManager,
this.authenticationConverter);
AuthenticationConverter converter2 = mock(AuthenticationConverter.class);
AuthenticationFilter filter2 = new AuthenticationFilter(this.authenticationManager, converter2);
FilterChain chain = new MockFilterChain(mock(Servlet.class), filter1, filter2);
chain.doFilter(request, response);
verify(this.authenticationConverter).convert(any());
verify(converter2).convert(any());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@@ -534,4 +534,17 @@ class StrictServerWebExchangeFirewallTests {
.isThrownBy(() -> headers.get(invalidHeaderName));
}
// gh-16978
@Test
void getMutatedFirewalledExchangeHeadersGetHeaderWhenNotAllowedHeaderNameThenException() {
String invalidHeaderName = "bad name";
this.firewall.setAllowedHeaderNames((name) -> !name.equals(invalidHeaderName));
ServerWebExchange exchange = getFirewalledExchange();
var mutatedRequest = exchange.getRequest().mutate().method(HttpMethod.POST).build();
var mutatedExchange = exchange.mutate().request(mutatedRequest).build();
HttpHeaders headers = mutatedExchange.getRequest().getHeaders();
assertThatExceptionOfType(ServerExchangeRejectedException.class)
.isThrownBy(() -> headers.get(invalidHeaderName));
}
}