Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c17cfae36 | |||
| 342735043d | |||
| 779541b340 | |||
| 5b293d2116 | |||
| 18e88366d2 | |||
| aeafcc1377 | |||
| 48babb7efa | |||
| f026e29771 | |||
| 620e6e0c34 | |||
| 4ebfa2c804 | |||
| f03224fe7f | |||
| 3feb809b35 | |||
| 771d9cd8b6 | |||
| a580856bb2 | |||
| 9b7a110704 | |||
| db37bdfe94 | |||
| ce012a4661 | |||
| 629540f9d8 | |||
| 96d1763fc4 | |||
| 98f9306a7c | |||
| 8efbbb3eb5 | |||
| 681681cbb8 | |||
| 612909ac4f | |||
| 54f7eacae6 | |||
| 5fb6f5768c | |||
| 28f98b3351 | |||
| ed96e2cddf | |||
| 97f6ca6f82 | |||
| ecc20ceffd | |||
| e147b22130 | |||
| d2cddb7e2d | |||
| 67e1832922 | |||
| 0426d27698 | |||
| 7afadfc0ef | |||
| 5f2a8c46d7 | |||
| 7200f76ac1 | |||
| 094b71b329 | |||
| 491f0f647c | |||
| ca0140c586 | |||
| 17e9fec6eb | |||
| 1db8734101 | |||
| b5f42b509b | |||
| 90936537dc | |||
| a8fcfaa428 | |||
| c20100dab7 | |||
| 4b44a2d924 | |||
| 1f27b18398 | |||
| e8b9a35494 | |||
| c4b773b150 | |||
| 82e5f62079 | |||
| 4257a97504 | |||
| 30bc2634d7 | |||
| 461d6edd85 | |||
| 13ca7ac4d4 | |||
| ee13216882 | |||
| c4f061c63d | |||
| 0d2315cf3a | |||
| 2c6d053ceb | |||
| ff4745a461 | |||
| 76b5d17c83 | |||
| 38a7ffcc9b | |||
| 6f55fc60bb | |||
| d0491c07e9 | |||
| 486c5118d2 | |||
| d02ab50577 | |||
| 17d8293be1 | |||
| 0686b461af |
@@ -5,8 +5,8 @@ on:
|
||||
tags: '**'
|
||||
repository_dispatch:
|
||||
types: request-build-reference # legacy
|
||||
#schedule:
|
||||
#- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
workflow_dispatch:
|
||||
permissions: read-all
|
||||
jobs:
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
# List of active maintenance branches.
|
||||
branch: [ main, 6.0.x, 5.8.x, 5.7.x ]
|
||||
branch: [ main, 6.0.x, 5.8.x, 5.7.x, 5.6.x ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
+196
-118
@@ -1,154 +1,232 @@
|
||||
= Contributing to Spring Security
|
||||
_Have something you'd like to contribute to the framework? We welcome pull requests, but ask that you carefully read this document first to understand how best to submit them; what kind of changes are likely to be accepted; and what to expect from the Spring Security team when evaluating your submission._
|
||||
|
||||
First off, thank you for taking the time to contribute! :+1: :tada:
|
||||
_Please refer back to this document as a checklist before issuing any pull request; this will save time for everyone!_
|
||||
|
||||
== Table of Contents
|
||||
= Code of Conduct
|
||||
|
||||
* <<code-of-conduct>>
|
||||
* <<how-to-contribute>>
|
||||
* <<ask-questions>>
|
||||
* <<find-an-issue>>
|
||||
* <<create-an-issue>>
|
||||
* <<issue-lifecycle>>
|
||||
* <<submit-a-pull-request>>
|
||||
* <<build-from-source>>
|
||||
* <<code-style>>
|
||||
Please see our https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[code of conduct].
|
||||
|
||||
[[code-of-conduct]]
|
||||
== Code of Conduct
|
||||
= Similar but different
|
||||
|
||||
This project is governed by the https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[Spring code of conduct].
|
||||
By participating you are expected to uphold this code.
|
||||
Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
||||
Each Spring module is slightly different from one another in terms of team size, number of issues, etc. Therefore, each project is managed slightly different. You will notice that this document is very similar to the https://github.com/spring-projects/spring-framework/wiki/Contributor-guidelines[Spring Framework Contributor guidelines]. However, there are some subtle differences between the two documents, so please be sure to read this document thoroughly.
|
||||
|
||||
[[how-to-contribute]]
|
||||
== How to Contribute
|
||||
= Importing into IDE
|
||||
|
||||
[[ask-questions]]
|
||||
=== Ask Questions
|
||||
The following provides information on setting up a development environment that can run the sample in https://www.springsource.org/sts[Spring Tool Suite 3.6.0+]. Other IDE's should work using Gradle's IDE support, but have not been tested.
|
||||
|
||||
If you have a question, check Stack Overflow using
|
||||
https://stackoverflow.com/questions/tagged/spring-security+or+spring-ldap+or+spring-authorization-server+or+spring-session?tab=Newest[this list of tags].
|
||||
Find an existing discussion, or start a new one if necessary.
|
||||
* IDE Setup
|
||||
** Install Spring Tool Suite 3.6.0+
|
||||
** You will need the following plugins installed (can be found on the Extensions Page)
|
||||
*** Gradle Eclipse
|
||||
*** Groovy Eclipse
|
||||
* Importing the project into Spring Tool Suite
|
||||
** File -> Import… -> Gradle Project
|
||||
|
||||
If you believe there is an issue, search through https://github.com/spring-projects/spring-security/issues[existing issues] trying a few different ways to find discussions, past or current, that are related to the issue.
|
||||
Reading those discussions helps you to learn about the issue, and helps us to make a decision.
|
||||
As of new versions of Spring Tool Suite, you might need to install Groovy Eclipse pointing directly to the updated plugin location. To install Groovy Eclipse on Spring Tool Suite based on Eclipse Oxigen you must do the following steps:
|
||||
|
||||
[[find-an-issue]]
|
||||
=== Find an Existing Issue
|
||||
Help -> Install New Software… -> Add the following URL into _Work with_ field:
|
||||
https://dist.springsource.org/snapshot/GRECLIPSE/e4.7/[https://dist.springsource.org/snapshot/GRECLIPSE/e4.7/]
|
||||
|
||||
There are many issues in Spring Security with the labels https://github.com/spring-projects/spring-security/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+ideal-for-contribution%22[`ideal-for-contribution`] or https://github.com/spring-projects/spring-security/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+first-timers-only%22[`first-timers-only`] that are a great way to contribute to a discussion or <<submit-a-pull-request,to a PR>>.
|
||||
You can volunteer by commenting on these tickets, and we will assign them to you.
|
||||
= Understand the basics
|
||||
|
||||
[[create-an-issue]]
|
||||
=== Create an Issue
|
||||
Not sure what a pull request is, or how to submit one? Take a look at GitHub's excellent https://help.github.com/articles/using-pull-requests[help documentation first].
|
||||
|
||||
Reporting an issue or making a feature request is a great way to contribute.
|
||||
Your feedback and the conversations that result from it provide a continuous flow of ideas.
|
||||
However, before creating a ticket, please take the time to <<ask-questions,ask and research>> first.
|
||||
= Search GitHub issues; create an issue if necessary
|
||||
|
||||
If you create an issue after a discussion on Stack Overflow, please provide a description in the issue instead of simply referring to Stack Overflow.
|
||||
The issue tracker is an important place of record for design discussions and should be self-sufficient.
|
||||
Is there already an issue that addresses your concern? Do a bit of searching in our https://github.com/spring-projects/spring-security/issues[GitHub issues] to see if you can find something similar. If not, please create a new issue before submitting a pull request unless the change is not a user facing issue.
|
||||
|
||||
Once you're ready, create an issue on https://github.com/spring-projects/spring-security/issues[GitHub].
|
||||
= Discuss non-trivial contribution ideas with committers
|
||||
|
||||
Many issues are caused by subtle behavior, typos, and unintended configuration.
|
||||
Creating a https://stackoverflow.com/help/minimal-reproducible-example[Minimal Reproducible Example] (starting with https://start.spring.io for example) of the problem helps the team quickly triage your issue and get to the core of the problem.
|
||||
If you're considering anything more than correcting a typo or fixing a minor bug, please discuss it on the https://gitter.im/spring-projects/spring-security[Spring Security Gitter] before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
|
||||
|
||||
We love contributors, and we may ask you to <<submit-a-pull-request,submit a PR with a fix>>.
|
||||
= Sign the Contributor License Agreement
|
||||
|
||||
[[issue-lifecycle]]
|
||||
=== Issue Lifecycle
|
||||
If you have not previously done so, please fill out and submit the https://cla.pivotal.io/sign/spring[Contributor License Agreement].
|
||||
|
||||
When an issue is first created, it is flagged `waiting-for-triage` waiting for a team member to triage it.
|
||||
Once the issue has been reviewed, the team may ask for further information if needed, and based on the findings, the issue is either assigned a target branch (or no branch if a feature) or is closed with a specific status.
|
||||
The target branch is https://spring.io/projects/spring-security#support[the earliest supported branch] where <<choose-a-branch,the change will be applied>>.
|
||||
= Create your branch from oldest maintenance branch
|
||||
|
||||
When a fix is ready, the issue is closed and may still be re-opened until the fix is released.
|
||||
After that the issue will typically no longer be reopened.
|
||||
In rare cases if the issue was not at all fixed, the issue may be re-opened.
|
||||
In most cases however any follow-up reports will need to be created as new issues with a fresh description.
|
||||
Create your topic branch to be submitted as a pull request from the oldest impacted and supported maintenance branch.
|
||||
You can find the supported versions by looking at the https://github.com/spring-projects/spring-security/milestones[milestones page].
|
||||
Switch to a branch named `<major>.<minor>.x` from the smallest milestone in the format of `<major>.<minor>.<patch>(-<prerelease>)`.
|
||||
The spring team will ensure the code gets merged forward into additional branches.
|
||||
|
||||
[[build-from-source]]
|
||||
=== Build from Source
|
||||
= Use short branch names
|
||||
|
||||
See https://github.com/spring-projects/spring-security/tree/main#building-from-source[Build from Source] for instructions on how to check out, build, and import the Spring Security source code into your IDE.
|
||||
Branches used when submitting pull requests should preferably be named according to GitHub issues, e.g. `gh-1234` or `gh-1234-fix-npe`. Otherwise, use succinct, lower-case, dash (`-`) delimited names, such as `fix-warnings` or `fix-typo`. This is important, because branch names show up in the merge commits that result from accepting pull requests, and should be as expressive and concise as possible.
|
||||
|
||||
[[code-style]]
|
||||
=== Source Code Style
|
||||
= Keep commits focused
|
||||
|
||||
The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize.
|
||||
Remember each ticket should be focused on a single item of interest since the tickets are used to produce the changelog. Since each commit should be tied to a single GitHub issue, ensure that your commits are focused. For example, do not include an update to a transitive library in your commit unless the GitHub is to update the library. Reviewing your commits is essential before sending a pull request.
|
||||
|
||||
To format the code as well as check the style, run `./gradle format check`.
|
||||
= Mind the whitespace
|
||||
|
||||
[[submit-a-pull-request]]
|
||||
=== Submit a Pull Request
|
||||
Please carefully follow the whitespace and formatting conventions already present in the framework.
|
||||
|
||||
We are excited for your pull request! :heart:
|
||||
. Tabs, not spaces
|
||||
. Unix (LF), not dos (CRLF) line endings
|
||||
. Eliminate all trailing whitespace
|
||||
. Aim to wrap code at 120 characters, but favor readability over wrapping
|
||||
. Preserve existing formatting; i.e. do not reformat code for its own sake
|
||||
. Search the codebase using `git grep` and other tools to discover common naming conventions, etc.
|
||||
. UTF-8 encoding for Java sources and XML files
|
||||
|
||||
Please do your best to follow these steps.
|
||||
Don't worry if you don't get them all correct the first time, we will help you.
|
||||
Whitespace management tips
|
||||
|
||||
. You can use the https://marketplace.eclipse.org/content/anyedit-tools[AnyEdit Eclipse plugin] to ensure spaces are used and to clean up trailing whitespaces.
|
||||
. Use Git's `pre-commit.sample` hook to prevent invalid whitespace from being pushed out. You can enable it by moving `.git/hooks/pre-commit.sample` to `.git/hooks/pre-commit` and ensuring it is executable. For more information on hooks refer to https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks[https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks].
|
||||
|
||||
= Add Apache license header to all new classes
|
||||
|
||||
[[sign-cla]]
|
||||
1. If you have not previously done so, please sign the https://cla.spring.io/sign/spring[Contributor License Agreement].
|
||||
You will be reminded automatically when you submit the PR.
|
||||
[[create-an-issue]]
|
||||
1. Must you https://github.com/spring-projects/spring-security/issues/new/choose[create an issue] first? No, but it is recommended for features and larger bug fixes. It's easier discuss with the team first to determine the right fix or enhancement.
|
||||
For typos and straightforward bug fixes, starting with a pull request is encouraged.
|
||||
Please include a description for context and motivation.
|
||||
Note that the team may close your pull request if it's not a fit for the project.
|
||||
[[choose-a-branch]]
|
||||
1. Always check out the branch indicated in the milestone and submit pull requests against it (for example, for milestone `5.8.3` use the `5.8.x` branch).
|
||||
If there is no milestone, choose `main`.
|
||||
Once merged, the fix will be forwarded-ported to applicable branches including `main`.
|
||||
[[create-a-local-branch]]
|
||||
1. Create a local branch
|
||||
If this is for an issue, consider a branch name with the issue number, like `gh-22276`.
|
||||
[[write-tests]]
|
||||
1. Add JUnit Tests for your changes
|
||||
[[update-copyright]]
|
||||
1. In all files you edited, if the copyright header is of the form 2002-20xx, update the final copyright year to the current year.
|
||||
[[add-since]]
|
||||
1. If on `main`, add `@since` JavaDoc attributes to new public APIs that your PR adds
|
||||
[[change-rnc]]
|
||||
1. If you are updating the XSD, please instead update the RNC file and then run `./gradlew :spring-security-config:rncToXsd`.
|
||||
[[format-code]]
|
||||
1. For each commit, build the code using `./gradlew format check`.
|
||||
This command ensures the code meets most of <<code-style,the style guide>>; a notable exception is import order.
|
||||
[[commit-atomically]]
|
||||
1. Choose the granularity of your commits consciously and squash commits that represent
|
||||
multiple edits or corrections of the same logical change.
|
||||
See https://git-scm.com/book/en/Git-Tools-Rewriting-History[Rewriting History section of Pro Git] for an overview of streamlining the commit history.
|
||||
[[format-commit-messages]]
|
||||
1. Format commit messages using 55 characters for the subject line, 72 characters per line
|
||||
for the description, followed by the issue fixed, for example, `Closes gh-22276`.
|
||||
See the https://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project#Commit-Guidelines[Commit Guidelines section of Pro Git] for best practices around commit messages, and use `git log` to see some examples.
|
||||
Present tense is preferred.
|
||||
+
|
||||
[indent=0]
|
||||
----
|
||||
Address NullPointerException
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
Closes gh-22276
|
||||
----
|
||||
[[reference-issue]]
|
||||
1. If there is a prior issue, reference the GitHub issue number in the description of the pull request.
|
||||
+
|
||||
[indent=0]
|
||||
----
|
||||
Closes gh-22276
|
||||
package ...;
|
||||
----
|
||||
|
||||
If accepted, your contribution may be heavily modified as needed prior to merging.
|
||||
You will likely retain author attribution for your Git commits granted that the bulk of your changes remain intact.
|
||||
You may also be asked to rework the submission.
|
||||
= Update Apache license header to modified files as necessary
|
||||
|
||||
If asked to make corrections, simply push the changes against the same branch, and your pull request will be updated.
|
||||
In other words, you do not need to create a new pull request when asked to make changes.
|
||||
When it is time to merge, you'll be asked to squash your commits.
|
||||
Always check the date range in the license header. For example, if you've modified a file in 2020 whose header still reads
|
||||
|
||||
==== Participate in Reviews
|
||||
----
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
----
|
||||
|
||||
Helping to review pull requests is another great way to contribute.
|
||||
Your feedback can help to shape the implementation of new features.
|
||||
When reviewing pull requests, however, please refrain from approving or rejecting a PR unless you are a core committer for Spring Security.
|
||||
then be sure to update it to the current year appropriately (e.g. 2020)
|
||||
|
||||
----
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
----
|
||||
|
||||
= Use @since tags for newly-added public API types and methods
|
||||
|
||||
Example:
|
||||
|
||||
----
|
||||
/**
|
||||
* …
|
||||
*
|
||||
* @author First Last
|
||||
* @since 5.4
|
||||
* @see …
|
||||
*/
|
||||
----
|
||||
|
||||
= Submit JUnit test cases for all behavior changes
|
||||
|
||||
Search the codebase to find related unit tests and add additional `@Test` methods within.
|
||||
|
||||
. Any new tests should end in the name `Tests` (note this is plural). For example, a valid name would be `FilterChainProxyTests`. An invalid name would be `FilterChainProxyTest`.
|
||||
. New test methods should not start with test. This is an old JUnit3 convention and is not necessary since the method is annotated with `@Test`.
|
||||
|
||||
= Update spring-security-x.y.rnc for schema changes
|
||||
|
||||
Update the https://www.relaxng.org[RELAX NG] schema `spring-security-x.y.rnc` instead of `spring-security-x.y.xsd` if you contribute changes to supported XML configuration. The XML schema file can be generated the following Gradle task:
|
||||
|
||||
----
|
||||
./gradlew :spring-security-config:rncToXsd
|
||||
----
|
||||
|
||||
Changes to the XML schema will be overwritten by the Gradle build task.
|
||||
|
||||
= Squash commits
|
||||
|
||||
Use `git rebase --interactive`, `git add --patch` and other tools to "squash" multiple commits into atomic changes. In addition to the man pages for `git`, there are https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History[many resources online] to help you understand how these tools work.
|
||||
|
||||
= Use real name in git commits
|
||||
|
||||
Please configure Git to use your real first and last name for any commits you intend to submit as pull requests. Make sure the name is properly capitalized as submitted to the https://cla.pivotal.io[Pivotal Contributor License Agreement]:
|
||||
|
||||
----
|
||||
First Last <user@mail.com>
|
||||
----
|
||||
|
||||
This helps ensure traceability against the CLA, and also goes a long way to ensuring useful output from tools like Git shortlog and others.
|
||||
|
||||
You can configure this globally:
|
||||
|
||||
----
|
||||
git config --global user.name "First Last"
|
||||
git config --global user.email user@example.com
|
||||
----
|
||||
|
||||
or locally for the current repository by omitting the `--global` flag:
|
||||
|
||||
----
|
||||
git config user.name "First Last"
|
||||
git config user.email user@example.com
|
||||
----
|
||||
|
||||
= Format commit messages
|
||||
|
||||
. Keep the subject line to 50 characters or less if possible
|
||||
. Do not end the subject line with a period
|
||||
. In the body of the commit message, explain how things worked before this commit, what has changed, and how things work now
|
||||
. Include `Closes gh-<issue-number>` at the end if this fixes a GitHub issue
|
||||
. Avoid markdown, including back-ticks identifying code
|
||||
|
||||
Example:
|
||||
|
||||
----
|
||||
Short (50 chars or less) summary of changes
|
||||
|
||||
More detailed explanatory text, if necessary. Wrap it to about 72
|
||||
characters or so. In some contexts, the first line is treated as the
|
||||
subject of an email and the rest of the text as the body. The blank
|
||||
line separating the summary from the body is critical (unless you omit
|
||||
the body entirely); tools like rebase can get confused if you run the
|
||||
two together.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
- Typically a hyphen or asterisk is used for the bullet, preceded by a
|
||||
single space, with blank lines in between, but conventions vary here
|
||||
|
||||
Closes gh-123
|
||||
----
|
||||
|
||||
|
||||
= Run all tests prior to submission
|
||||
|
||||
----
|
||||
./gradlew clean build integrationTest
|
||||
----
|
||||
|
||||
= Submit your pull request
|
||||
|
||||
*Subject line:*
|
||||
|
||||
Follow the same conventions for pull request subject lines as mentioned above for commit message subject lines.
|
||||
|
||||
*In the body:*
|
||||
|
||||
. Explain your use case. What led you to submit this change? Why were existing mechanisms in the framework insufficient? Make a case that this is a general-purpose problem and that yours is a general-purpose solution, etc
|
||||
. Add any additional information and ask questions; start a conversation, or continue one from GitHub Issues
|
||||
. Mention any GitHub Issues
|
||||
. Also mention that you have submitted the CLA as described above
|
||||
Note that for pull requests containing a single commit, GitHub will default the subject line and body of the pull request to match the subject line and body of the commit message. This is fine, but please also include the items above in the body of the request.
|
||||
|
||||
= Mention your pull request on the associated GitHub issue
|
||||
|
||||
Add a comment to the associated GitHub issue(s) linking to your new pull request.
|
||||
|
||||
= Expect discussion and rework
|
||||
|
||||
The Spring team takes a very conservative approach to accepting contributions to the framework. This is to keep code quality and stability as high as possible, and to keep complexity at a minimum. Your changes, if accepted, may be heavily modified prior to merging. You will retain "Author:" attribution for your Git commits granted that the bulk of your changes remain intact. You may be asked to rework the submission for style (as explained above) and/or substance. Again, we strongly recommend discussing any serious submissions with the Spring Framework team prior to engaging in serious development work.
|
||||
|
||||
Note that you can always force push (`git push -f`) reworked / rebased commits against the branch used to submit your pull request. i.e. you do not need to issue a new pull request when asked to make changes.
|
||||
|
||||
+1
-1
@@ -59,9 +59,9 @@ The scheduled release process currently runs every Monday but only releases when
|
||||
The automated release process occurs on the following branches:
|
||||
|
||||
* `main`
|
||||
* `6.0.x`
|
||||
* `5.8.x`
|
||||
* `5.7.x`
|
||||
* `5.6.x`
|
||||
|
||||
For each of the above branches, the automated process performs the following checks before proceeding with the release:
|
||||
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
import io.spring.gradle.IncludeRepoTask
|
||||
import trang.RncToXsd
|
||||
|
||||
buildscript {
|
||||
dependencies {
|
||||
@@ -174,7 +175,7 @@ if (hasProperty('buildScan')) {
|
||||
|
||||
nohttp {
|
||||
source.exclude "buildSrc/build/**"
|
||||
|
||||
source.builtBy(project(':spring-security-config').tasks.withType(RncToXsd))
|
||||
}
|
||||
|
||||
tasks.register('cloneSamples', IncludeRepoTask) {
|
||||
|
||||
@@ -86,8 +86,8 @@ dependencies {
|
||||
implementation localGroovy()
|
||||
|
||||
implementation 'io.github.gradle-nexus:publish-plugin:1.1.0'
|
||||
implementation 'io.projectreactor:reactor-core:3.5.8'
|
||||
implementation 'org.gretty:gretty:4.0.3'
|
||||
implementation 'io.projectreactor:reactor-core:3.5.9'
|
||||
implementation 'org.gretty:gretty:3.0.9'
|
||||
implementation 'com.apollographql.apollo:apollo-runtime:2.4.5'
|
||||
implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
|
||||
implementation 'com.github.spullara.mustache.java:compiler:0.9.4'
|
||||
|
||||
@@ -34,7 +34,7 @@ class JacocoPlugin implements Plugin<Project> {
|
||||
project.tasks.check.dependsOn project.tasks.jacocoTestReport
|
||||
|
||||
project.jacoco {
|
||||
toolVersion = '0.8.7'
|
||||
toolVersion = '0.8.9'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-4
@@ -34,6 +34,14 @@ class RepositoryConventionPlugin implements Plugin<Project> {
|
||||
if (forceMavenRepositories?.contains('local')) {
|
||||
mavenLocal()
|
||||
}
|
||||
maven {
|
||||
name = 'shibboleth'
|
||||
url = 'https://build.shibboleth.net/nexus/content/repositories/releases/'
|
||||
content {
|
||||
includeGroupByRegex('org\\.opensaml.*')
|
||||
includeGroupByRegex('net\\.shibboleth.*')
|
||||
}
|
||||
}
|
||||
mavenCentral()
|
||||
if (isSnapshot) {
|
||||
maven {
|
||||
@@ -67,12 +75,11 @@ class RepositoryConventionPlugin implements Plugin<Project> {
|
||||
password project.artifactoryPassword
|
||||
}
|
||||
}
|
||||
content {
|
||||
excludeGroup('net.minidev')
|
||||
}
|
||||
url = 'https://repo.spring.io/release/'
|
||||
}
|
||||
maven {
|
||||
name = 'shibboleth'
|
||||
url = 'https://build.shibboleth.net/nexus/content/repositories/releases/'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.api.tasks.bundling.Zip
|
||||
import org.springframework.gradle.xsd.CreateVersionlessXsdTask
|
||||
|
||||
public class SchemaZipPlugin implements Plugin<Project> {
|
||||
|
||||
@@ -15,7 +16,10 @@ public class SchemaZipPlugin implements Plugin<Project> {
|
||||
schemaZip.archiveClassifier = 'schema'
|
||||
schemaZip.description = "Builds -${schemaZip.archiveClassifier} archive containing all " +
|
||||
"XSDs for deployment at static.springframework.org/schema."
|
||||
|
||||
def versionlessXsd = project.tasks.create("versionlessXsd", CreateVersionlessXsdTask) {
|
||||
description = "Generates spring-security.xsd"
|
||||
versionlessXsdFile = project.layout.buildDirectory.file("versionlessXsd/spring-security.xsd")
|
||||
}
|
||||
project.rootProject.subprojects.each { module ->
|
||||
|
||||
module.getPlugins().withType(JavaPlugin.class).all {
|
||||
@@ -36,17 +40,14 @@ public class SchemaZipPlugin implements Plugin<Project> {
|
||||
duplicatesStrategy 'exclude'
|
||||
from xsdFile.path
|
||||
}
|
||||
}
|
||||
File symlink = module.sourceSets.main.resources.find {
|
||||
it.path.endsWith('org/springframework/security/config/spring-security.xsd')
|
||||
}
|
||||
if (symlink != null) {
|
||||
schemaZip.into('security') {
|
||||
duplicatesStrategy 'exclude'
|
||||
from symlink.path
|
||||
}
|
||||
versionlessXsd.getInputFiles().from(xsdFile.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schemaZip.into("security") {
|
||||
from(versionlessXsd.getOutputs())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2019-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.xsd;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.tasks.*;
|
||||
import org.gradle.work.DisableCachingByDefault;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Creates the spring-security.xsd automatically
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@DisableCachingByDefault(because = "not worth it")
|
||||
public abstract class CreateVersionlessXsdTask extends DefaultTask {
|
||||
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getInputFiles();
|
||||
|
||||
@OutputFile
|
||||
abstract RegularFileProperty getVersionlessXsdFile();
|
||||
|
||||
@TaskAction
|
||||
void createVersionlessXsd() throws IOException {
|
||||
XsdFileMajorMinorVersion largest = null;
|
||||
ConfigurableFileCollection inputFiles = getInputFiles();
|
||||
if (inputFiles.isEmpty()) {
|
||||
throw new IllegalStateException("No Inputs configured");
|
||||
}
|
||||
for (File file : inputFiles) {
|
||||
XsdFileMajorMinorVersion current = XsdFileMajorMinorVersion.create(file);
|
||||
if (current == null) {
|
||||
continue;
|
||||
}
|
||||
if (largest == null) {
|
||||
largest = current;
|
||||
}
|
||||
else if (current.getVersion().isGreaterThan(largest.getVersion())) {
|
||||
largest = current;
|
||||
}
|
||||
}
|
||||
if (largest == null) {
|
||||
throw new IllegalStateException("Could not create versionless xsd file because no files matching spring-security-<digit>.xsd were found in " + inputFiles.getFiles());
|
||||
}
|
||||
Path to = getVersionlessXsdFile().getAsFile().get().toPath();
|
||||
Path from = largest.getFile().toPath();
|
||||
Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
static class XsdFileMajorMinorVersion {
|
||||
private final File file;
|
||||
|
||||
private final MajorMinorVersion version;
|
||||
|
||||
private XsdFileMajorMinorVersion(File file, MajorMinorVersion version) {
|
||||
this.file = file;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
private static final Pattern FILE_MAJOR_MINOR_VERSION_PATTERN = Pattern.compile("^spring-security-(\\d+)\\.(\\d+)\\.xsd$");
|
||||
|
||||
/**
|
||||
* If matches xsd with major minor version (e.g. spring-security-5.1.xsd returns it, otherwise null
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
static XsdFileMajorMinorVersion create(File file) {
|
||||
String fileName = file.getName();
|
||||
Matcher matcher = FILE_MAJOR_MINOR_VERSION_PATTERN.matcher(fileName);
|
||||
if (!matcher.find()) {
|
||||
return null;
|
||||
}
|
||||
int major = Integer.parseInt(matcher.group(1));
|
||||
int minor = Integer.parseInt(matcher.group(2));
|
||||
MajorMinorVersion version = new MajorMinorVersion(major, minor);
|
||||
return new XsdFileMajorMinorVersion(file, version);
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public MajorMinorVersion getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
static class MajorMinorVersion {
|
||||
private final int major;
|
||||
|
||||
private final int minor;
|
||||
|
||||
MajorMinorVersion(int major, int minor) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
}
|
||||
|
||||
public int getMajor() {
|
||||
return major;
|
||||
}
|
||||
|
||||
public int getMinor() {
|
||||
return minor;
|
||||
}
|
||||
|
||||
public boolean isGreaterThan(MajorMinorVersion version) {
|
||||
if (getMajor() > version.getMajor()) {
|
||||
return true;
|
||||
}
|
||||
if (getMajor() < version.getMajor()) {
|
||||
return false;
|
||||
}
|
||||
if (getMinor() > version.getMinor()) {
|
||||
return true;
|
||||
}
|
||||
if (getMinor() < version.getMinor()) {
|
||||
return false;
|
||||
}
|
||||
// they are equal
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -125,27 +125,27 @@ public class RepositoryConventionPluginTests {
|
||||
|
||||
private void assertSnapshotRepository(RepositoryHandler repositories) {
|
||||
assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(5);
|
||||
assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString())
|
||||
.isEqualTo("https://repo.maven.apache.org/maven2/");
|
||||
assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString())
|
||||
.isEqualTo("https://repo.spring.io/snapshot/");
|
||||
.isEqualTo("https://repo.maven.apache.org/maven2/");
|
||||
assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
|
||||
.isEqualTo("https://repo.spring.io/snapshot/");
|
||||
assertThat(((MavenArtifactRepository) repositories.get(3)).getUrl().toString())
|
||||
.isEqualTo("https://repo.spring.io/milestone/");
|
||||
}
|
||||
|
||||
private void assertMilestoneRepository(RepositoryHandler repositories) {
|
||||
assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(4);
|
||||
assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString())
|
||||
.isEqualTo("https://repo.maven.apache.org/maven2/");
|
||||
assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString())
|
||||
.isEqualTo("https://repo.maven.apache.org/maven2/");
|
||||
assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
|
||||
.isEqualTo("https://repo.spring.io/milestone/");
|
||||
}
|
||||
|
||||
private void assertReleaseRepository(RepositoryHandler repositories) {
|
||||
assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(3);
|
||||
assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString())
|
||||
.isEqualTo("https://repo.maven.apache.org/maven2/");
|
||||
assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString())
|
||||
.isEqualTo("https://repo.maven.apache.org/maven2/");
|
||||
assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
|
||||
.isEqualTo("https://repo.spring.io/release/");
|
||||
}
|
||||
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2019-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.xsd;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.gradle.xsd.CreateVersionlessXsdTask.MajorMinorVersion;
|
||||
import org.springframework.gradle.xsd.CreateVersionlessXsdTask.XsdFileMajorMinorVersion;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class CreateVersionlessXsdTaskTests {
|
||||
|
||||
@Test
|
||||
void xsdCreateWhenValid() {
|
||||
File file = new File("spring-security-2.0.xsd");
|
||||
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
|
||||
assertThat(xsdFile).isNotNull();
|
||||
assertThat(xsdFile.getFile()).isEqualTo(file);
|
||||
assertThat(xsdFile.getVersion().getMajor()).isEqualTo(2);
|
||||
assertThat(xsdFile.getVersion().getMinor()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void xsdCreateWhenPatchReleaseThenNull() {
|
||||
File file = new File("spring-security-2.0.1.xsd");
|
||||
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
|
||||
assertThat(xsdFile).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void xsdCreateWhenNotXsdFileThenNull() {
|
||||
File file = new File("spring-security-2.0.txt");
|
||||
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
|
||||
assertThat(xsdFile).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void xsdCreateWhenNotStartWithSpringSecurityThenNull() {
|
||||
File file = new File("spring-securityNO-2.0.xsd");
|
||||
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
|
||||
assertThat(xsdFile).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isGreaterWhenMajorLarger() {
|
||||
MajorMinorVersion larger = new MajorMinorVersion(2,0);
|
||||
MajorMinorVersion smaller = new MajorMinorVersion(1,0);
|
||||
assertThat(larger.isGreaterThan(smaller)).isTrue();
|
||||
assertThat(smaller.isGreaterThan(larger)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isGreaterWhenMinorLarger() {
|
||||
MajorMinorVersion larger = new MajorMinorVersion(1,1);
|
||||
MajorMinorVersion smaller = new MajorMinorVersion(1,0);
|
||||
assertThat(larger.isGreaterThan(smaller)).isTrue();
|
||||
assertThat(smaller.isGreaterThan(larger)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isGreaterWhenMajorAndMinorLarger() {
|
||||
MajorMinorVersion larger = new MajorMinorVersion(2,1);
|
||||
MajorMinorVersion smaller = new MajorMinorVersion(1,0);
|
||||
assertThat(larger.isGreaterThan(smaller)).isTrue();
|
||||
assertThat(smaller.isGreaterThan(larger)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isGreaterWhenSame() {
|
||||
MajorMinorVersion first = new MajorMinorVersion(1,0);
|
||||
MajorMinorVersion second = new MajorMinorVersion(1,0);
|
||||
assertThat(first.isGreaterThan(second)).isFalse();
|
||||
assertThat(second.isGreaterThan(first)).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
management platform(project(":spring-security-dependencies"))
|
||||
api project(':spring-security-core')
|
||||
api project(':spring-security-web')
|
||||
api 'org.apereo.cas.client:cas-client-core'
|
||||
api 'org.springframework:spring-beans'
|
||||
api 'org.springframework:spring-context'
|
||||
api 'org.springframework:spring-core'
|
||||
api 'org.springframework:spring-web'
|
||||
|
||||
optional 'com.fasterxml.jackson.core:jackson-databind'
|
||||
|
||||
provided 'jakarta.servlet:jakarta.servlet-api'
|
||||
|
||||
testImplementation "org.assertj:assertj-core"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-engine"
|
||||
testImplementation "org.mockito:mockito-core"
|
||||
testImplementation "org.mockito:mockito-junit-jupiter"
|
||||
testImplementation "org.springframework:spring-test"
|
||||
testImplementation 'org.skyscreamer:jsonassert'
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas;
|
||||
|
||||
/**
|
||||
* Sets the appropriate parameters for CAS's implementation of SAML (which is not
|
||||
* guaranteed to be actually SAML compliant).
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class SamlServiceProperties extends ServiceProperties {
|
||||
|
||||
public static final String DEFAULT_SAML_ARTIFACT_PARAMETER = "SAMLart";
|
||||
|
||||
public static final String DEFAULT_SAML_SERVICE_PARAMETER = "TARGET";
|
||||
|
||||
public SamlServiceProperties() {
|
||||
super.setArtifactParameter(DEFAULT_SAML_ARTIFACT_PARAMETER);
|
||||
super.setServiceParameter(DEFAULT_SAML_SERVICE_PARAMETER);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Stores properties related to this CAS service.
|
||||
* <p>
|
||||
* Each web application capable of processing CAS tickets is known as a service. This
|
||||
* class stores the properties that are relevant to the local CAS service, being the
|
||||
* application that is being secured by Spring Security.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class ServiceProperties implements InitializingBean {
|
||||
|
||||
public static final String DEFAULT_CAS_ARTIFACT_PARAMETER = "ticket";
|
||||
|
||||
public static final String DEFAULT_CAS_SERVICE_PARAMETER = "service";
|
||||
|
||||
private String service;
|
||||
|
||||
private boolean authenticateAllArtifacts;
|
||||
|
||||
private boolean sendRenew = false;
|
||||
|
||||
private String artifactParameter = DEFAULT_CAS_ARTIFACT_PARAMETER;
|
||||
|
||||
private String serviceParameter = DEFAULT_CAS_SERVICE_PARAMETER;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.hasLength(this.service, "service cannot be empty.");
|
||||
Assert.hasLength(this.artifactParameter, "artifactParameter cannot be empty.");
|
||||
Assert.hasLength(this.serviceParameter, "serviceParameter cannot be empty.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the service the user is authenticating to.
|
||||
* <p>
|
||||
* This service is the callback URL belonging to the local Spring Security System for
|
||||
* Spring secured application. For example,
|
||||
*
|
||||
* <pre>
|
||||
* https://www.mycompany.com/application/login/cas
|
||||
* </pre>
|
||||
* @return the URL of the service the user is authenticating to
|
||||
*/
|
||||
public final String getService() {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the <code>renew</code> parameter should be sent to the CAS login
|
||||
* URL and CAS validation URL.
|
||||
* <p>
|
||||
* If <code>true</code>, it will force CAS to authenticate the user again (even if the
|
||||
* user has previously authenticated). During ticket validation it will require the
|
||||
* ticket was generated as a consequence of an explicit login. High security
|
||||
* applications would probably set this to <code>true</code>. Defaults to
|
||||
* <code>false</code>, providing automated single sign on.
|
||||
* @return whether to send the <code>renew</code> parameter to CAS
|
||||
*/
|
||||
public final boolean isSendRenew() {
|
||||
return this.sendRenew;
|
||||
}
|
||||
|
||||
public final void setSendRenew(final boolean sendRenew) {
|
||||
this.sendRenew = sendRenew;
|
||||
}
|
||||
|
||||
public final void setService(final String service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public final String getArtifactParameter() {
|
||||
return this.artifactParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Request Parameter to look for when attempting to see if a CAS ticket
|
||||
* was sent from the server.
|
||||
* @param artifactParameter the id to use. Default is "ticket".
|
||||
*/
|
||||
public final void setArtifactParameter(final String artifactParameter) {
|
||||
this.artifactParameter = artifactParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Request parameter to look for when attempting to send a request to
|
||||
* CAS.
|
||||
* @return the service parameter to use. Default is "service".
|
||||
*/
|
||||
public final String getServiceParameter() {
|
||||
return this.serviceParameter;
|
||||
}
|
||||
|
||||
public final void setServiceParameter(final String serviceParameter) {
|
||||
this.serviceParameter = serviceParameter;
|
||||
}
|
||||
|
||||
public final boolean isAuthenticateAllArtifacts() {
|
||||
return this.authenticateAllArtifacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, then any non-null artifact (ticket) should be authenticated. Additionally,
|
||||
* the service will be determined dynamically in order to ensure the service matches
|
||||
* the expected value for this artifact.
|
||||
* @param authenticateAllArtifacts
|
||||
*/
|
||||
public final void setAuthenticateAllArtifacts(final boolean authenticateAllArtifacts) {
|
||||
this.authenticateAllArtifacts = authenticateAllArtifacts;
|
||||
}
|
||||
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
|
||||
/**
|
||||
* Temporary authentication object needed to load the user details service.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class CasAssertionAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
|
||||
private final Assertion assertion;
|
||||
|
||||
private final String ticket;
|
||||
|
||||
public CasAssertionAuthenticationToken(final Assertion assertion, final String ticket) {
|
||||
super(new ArrayList<>());
|
||||
this.assertion = assertion;
|
||||
this.ticket = ticket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.assertion.getPrincipal().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return this.ticket;
|
||||
}
|
||||
|
||||
public Assertion getAssertion() {
|
||||
return this.assertion;
|
||||
}
|
||||
|
||||
}
|
||||
-234
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
import org.apereo.cas.client.validation.TicketValidationException;
|
||||
import org.apereo.cas.client.validation.TicketValidator;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.core.userdetails.UserDetailsChecker;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationProvider} implementation that integrates with JA-SIG Central
|
||||
* Authentication Service (CAS).
|
||||
* <p>
|
||||
* This <code>AuthenticationProvider</code> is capable of validating
|
||||
* {@link CasServiceTicketAuthenticationToken} requests which contain a
|
||||
* <code>principal</code> name equal to either
|
||||
* {@link CasServiceTicketAuthenticationToken#CAS_STATEFUL_IDENTIFIER} or
|
||||
* {@link CasServiceTicketAuthenticationToken#CAS_STATELESS_IDENTIFIER}. It can also
|
||||
* validate a previously created {@link CasAuthenticationToken}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Scott Battaglia
|
||||
*/
|
||||
public class CasAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CasAuthenticationProvider.class);
|
||||
|
||||
private AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService;
|
||||
|
||||
private final UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
|
||||
private StatelessTicketCache statelessTicketCache = new NullStatelessTicketCache();
|
||||
|
||||
private String key;
|
||||
|
||||
private TicketValidator ticketValidator;
|
||||
|
||||
private ServiceProperties serviceProperties;
|
||||
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(this.authenticationUserDetailsService, "An authenticationUserDetailsService must be set");
|
||||
Assert.notNull(this.ticketValidator, "A ticketValidator must be set");
|
||||
Assert.notNull(this.statelessTicketCache, "A statelessTicketCache must be set");
|
||||
Assert.hasText(this.key,
|
||||
"A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
if (!supports(authentication.getClass())) {
|
||||
return null;
|
||||
}
|
||||
// If an existing CasAuthenticationToken, just check we created it
|
||||
if (authentication instanceof CasAuthenticationToken) {
|
||||
if (this.key.hashCode() != ((CasAuthenticationToken) authentication).getKeyHash()) {
|
||||
throw new BadCredentialsException(this.messages.getMessage("CasAuthenticationProvider.incorrectKey",
|
||||
"The presented CasAuthenticationToken does not contain the expected key"));
|
||||
}
|
||||
return authentication;
|
||||
}
|
||||
|
||||
// Ensure credentials are presented
|
||||
if ((authentication.getCredentials() == null) || "".equals(authentication.getCredentials())) {
|
||||
throw new BadCredentialsException(this.messages.getMessage("CasAuthenticationProvider.noServiceTicket",
|
||||
"Failed to provide a CAS service ticket to validate"));
|
||||
}
|
||||
|
||||
boolean stateless = (authentication instanceof CasServiceTicketAuthenticationToken token && token.isStateless());
|
||||
CasAuthenticationToken result = null;
|
||||
|
||||
if (stateless) {
|
||||
// Try to obtain from cache
|
||||
result = this.statelessTicketCache.getByTicketId(authentication.getCredentials().toString());
|
||||
}
|
||||
if (result == null) {
|
||||
result = this.authenticateNow(authentication);
|
||||
result.setDetails(authentication.getDetails());
|
||||
}
|
||||
if (stateless) {
|
||||
// Add to cache
|
||||
this.statelessTicketCache.putTicketInCache(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private CasAuthenticationToken authenticateNow(final Authentication authentication) throws AuthenticationException {
|
||||
try {
|
||||
Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(),
|
||||
getServiceUrl(authentication));
|
||||
UserDetails userDetails = loadUserByAssertion(assertion);
|
||||
this.userDetailsChecker.check(userDetails);
|
||||
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
|
||||
this.authoritiesMapper.mapAuthorities(userDetails.getAuthorities()), userDetails, assertion);
|
||||
}
|
||||
catch (TicketValidationException ex) {
|
||||
throw new BadCredentialsException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serviceUrl. If the {@link Authentication#getDetails()} is an instance of
|
||||
* {@link ServiceAuthenticationDetails}, then
|
||||
* {@link ServiceAuthenticationDetails#getServiceUrl()} is used. Otherwise, the
|
||||
* {@link ServiceProperties#getService()} is used.
|
||||
* @param authentication
|
||||
* @return
|
||||
*/
|
||||
private String getServiceUrl(Authentication authentication) {
|
||||
String serviceUrl;
|
||||
if (authentication.getDetails() instanceof ServiceAuthenticationDetails) {
|
||||
return ((ServiceAuthenticationDetails) authentication.getDetails()).getServiceUrl();
|
||||
}
|
||||
Assert.state(this.serviceProperties != null,
|
||||
"serviceProperties cannot be null unless Authentication.getDetails() implements ServiceAuthenticationDetails.");
|
||||
Assert.state(this.serviceProperties.getService() != null,
|
||||
"serviceProperties.getService() cannot be null unless Authentication.getDetails() implements ServiceAuthenticationDetails.");
|
||||
serviceUrl = this.serviceProperties.getService();
|
||||
logger.debug(LogMessage.format("serviceUrl = %s", serviceUrl));
|
||||
return serviceUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for retrieving the UserDetails based on the assertion. Default is
|
||||
* to call configured userDetailsService and pass the username. Deployers can override
|
||||
* this method and retrieve the user based on any criteria they desire.
|
||||
* @param assertion The CAS Assertion.
|
||||
* @return the UserDetails.
|
||||
*/
|
||||
protected UserDetails loadUserByAssertion(final Assertion assertion) {
|
||||
final CasAssertionAuthenticationToken token = new CasAssertionAuthenticationToken(assertion, "");
|
||||
return this.authenticationUserDetailsService.loadUserDetails(token);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
/**
|
||||
* Sets the UserDetailsService to use. This is a convenience method to invoke
|
||||
*/
|
||||
public void setUserDetailsService(final UserDetailsService userDetailsService) {
|
||||
this.authenticationUserDetailsService = new UserDetailsByNameServiceWrapper(userDetailsService);
|
||||
}
|
||||
|
||||
public void setAuthenticationUserDetailsService(
|
||||
final AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService) {
|
||||
this.authenticationUserDetailsService = authenticationUserDetailsService;
|
||||
}
|
||||
|
||||
public void setServiceProperties(final ServiceProperties serviceProperties) {
|
||||
this.serviceProperties = serviceProperties;
|
||||
}
|
||||
|
||||
protected String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public StatelessTicketCache getStatelessTicketCache() {
|
||||
return this.statelessTicketCache;
|
||||
}
|
||||
|
||||
protected TicketValidator getTicketValidator() {
|
||||
return this.ticketValidator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageSource(final MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
public void setStatelessTicketCache(final StatelessTicketCache statelessTicketCache) {
|
||||
this.statelessTicketCache = statelessTicketCache;
|
||||
}
|
||||
|
||||
public void setTicketValidator(final TicketValidator ticketValidator) {
|
||||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(final Class<?> authentication) {
|
||||
return (CasServiceTicketAuthenticationToken.class.isAssignableFrom(authentication))
|
||||
|| (CasAuthenticationToken.class.isAssignableFrom(authentication))
|
||||
|| (CasAssertionAuthenticationToken.class.isAssignableFrom(authentication));
|
||||
}
|
||||
|
||||
}
|
||||
-173
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Represents a successful CAS <code>Authentication</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Scott Battaglia
|
||||
*/
|
||||
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
|
||||
private final Object credentials;
|
||||
|
||||
private final Object principal;
|
||||
|
||||
private final UserDetails userDetails;
|
||||
|
||||
private final int keyHash;
|
||||
|
||||
private final Assertion assertion;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param key to identify if this object made by a given
|
||||
* {@link CasAuthenticationProvider}
|
||||
* @param principal typically the UserDetails object (cannot be <code>null</code>)
|
||||
* @param credentials the service/proxy ticket ID from CAS (cannot be
|
||||
* <code>null</code>)
|
||||
* @param authorities the authorities granted to the user (from the
|
||||
* {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
|
||||
* be <code>null</code>)
|
||||
* @param userDetails the user details (from the
|
||||
* {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
|
||||
* be <code>null</code>)
|
||||
* @param assertion the assertion returned from the CAS servers. It contains the
|
||||
* principal and how to obtain a proxy ticket for the user.
|
||||
* @throws IllegalArgumentException if a <code>null</code> was passed
|
||||
*/
|
||||
public CasAuthenticationToken(final String key, final Object principal, final Object credentials,
|
||||
final Collection<? extends GrantedAuthority> authorities, final UserDetails userDetails,
|
||||
final Assertion assertion) {
|
||||
this(extractKeyHash(key), principal, credentials, authorities, userDetails, assertion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for Jackson Deserialization support
|
||||
* @param keyHash hashCode of provided key to identify if this object made by a given
|
||||
* {@link CasAuthenticationProvider}
|
||||
* @param principal typically the UserDetails object (cannot be <code>null</code>)
|
||||
* @param credentials the service/proxy ticket ID from CAS (cannot be
|
||||
* <code>null</code>)
|
||||
* @param authorities the authorities granted to the user (from the
|
||||
* {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
|
||||
* be <code>null</code>)
|
||||
* @param userDetails the user details (from the
|
||||
* {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
|
||||
* be <code>null</code>)
|
||||
* @param assertion the assertion returned from the CAS servers. It contains the
|
||||
* principal and how to obtain a proxy ticket for the user.
|
||||
* @throws IllegalArgumentException if a <code>null</code> was passed
|
||||
* @since 4.2
|
||||
*/
|
||||
private CasAuthenticationToken(final Integer keyHash, final Object principal, final Object credentials,
|
||||
final Collection<? extends GrantedAuthority> authorities, final UserDetails userDetails,
|
||||
final Assertion assertion) {
|
||||
super(authorities);
|
||||
if ((principal == null) || "".equals(principal) || (credentials == null) || "".equals(credentials)
|
||||
|| (authorities == null) || (userDetails == null) || (assertion == null)) {
|
||||
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
|
||||
}
|
||||
this.keyHash = keyHash;
|
||||
this.principal = principal;
|
||||
this.credentials = credentials;
|
||||
this.userDetails = userDetails;
|
||||
this.assertion = assertion;
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
private static Integer extractKeyHash(String key) {
|
||||
Assert.hasLength(key, "key cannot be null or empty");
|
||||
return key.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof CasAuthenticationToken) {
|
||||
CasAuthenticationToken test = (CasAuthenticationToken) obj;
|
||||
if (!this.assertion.equals(test.getAssertion())) {
|
||||
return false;
|
||||
}
|
||||
if (this.getKeyHash() != test.getKeyHash()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + this.credentials.hashCode();
|
||||
result = 31 * result + this.principal.hashCode();
|
||||
result = 31 * result + this.userDetails.hashCode();
|
||||
result = 31 * result + this.keyHash;
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.assertion);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return this.credentials;
|
||||
}
|
||||
|
||||
public int getKeyHash() {
|
||||
return this.keyHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public Assertion getAssertion() {
|
||||
return this.assertion;
|
||||
}
|
||||
|
||||
public UserDetails getUserDetails() {
|
||||
return this.userDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(super.toString());
|
||||
sb.append(" Assertion: ").append(this.assertion);
|
||||
sb.append(" Credentials (Service/Proxy Ticket): ").append(this.credentials);
|
||||
return (sb.toString());
|
||||
}
|
||||
|
||||
}
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link org.springframework.security.core.Authentication} implementation that is
|
||||
* designed to process CAS service ticket.
|
||||
*
|
||||
* @author Hal Deadman
|
||||
* @since 6.1
|
||||
*/
|
||||
public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
static final String CAS_STATELESS_IDENTIFIER = "_cas_stateless_";
|
||||
|
||||
static final String CAS_STATEFUL_IDENTIFIER = "_cas_stateful_";
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
|
||||
private final String identifier;
|
||||
|
||||
private Object credentials;
|
||||
|
||||
/**
|
||||
* This constructor can be safely used by any code that wishes to create a
|
||||
* <code>CasServiceTicketAuthenticationToken</code>, as the {@link #isAuthenticated()}
|
||||
* will return <code>false</code>.
|
||||
*
|
||||
*/
|
||||
public CasServiceTicketAuthenticationToken(String identifier, Object credentials) {
|
||||
super(null);
|
||||
this.identifier = identifier;
|
||||
this.credentials = credentials;
|
||||
setAuthenticated(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor should only be used by <code>AuthenticationManager</code> or
|
||||
* <code>AuthenticationProvider</code> implementations that are satisfied with
|
||||
* producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
|
||||
* authentication token.
|
||||
* @param identifier
|
||||
* @param credentials
|
||||
* @param authorities
|
||||
*/
|
||||
public CasServiceTicketAuthenticationToken(String identifier, Object credentials,
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
super(authorities);
|
||||
this.identifier = identifier;
|
||||
this.credentials = credentials;
|
||||
super.setAuthenticated(true);
|
||||
}
|
||||
|
||||
public static CasServiceTicketAuthenticationToken stateful(Object credentials) {
|
||||
return new CasServiceTicketAuthenticationToken(CAS_STATEFUL_IDENTIFIER, credentials);
|
||||
}
|
||||
|
||||
public static CasServiceTicketAuthenticationToken stateless(Object credentials) {
|
||||
return new CasServiceTicketAuthenticationToken(CAS_STATELESS_IDENTIFIER, credentials);
|
||||
}
|
||||
|
||||
public boolean isStateless() {
|
||||
return CAS_STATELESS_IDENTIFIER.equals(this.identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return this.credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
|
||||
Assert.isTrue(!isAuthenticated,
|
||||
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
|
||||
super.setAuthenticated(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eraseCredentials() {
|
||||
super.eraseCredentials();
|
||||
this.credentials = null;
|
||||
}
|
||||
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
/**
|
||||
* Implementation of @link {@link StatelessTicketCache} that has no backing cache. Useful
|
||||
* in instances where storing of tickets for stateless session management is not required.
|
||||
* <p>
|
||||
* This is the default StatelessTicketCache of the @link {@link CasAuthenticationProvider}
|
||||
* to eliminate the unnecessary dependency on EhCache that applications have even if they
|
||||
* are not using the stateless session management.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @see CasAuthenticationProvider
|
||||
*/
|
||||
public final class NullStatelessTicketCache implements StatelessTicketCache {
|
||||
|
||||
/**
|
||||
* @return null since we are not storing any tickets.
|
||||
*/
|
||||
@Override
|
||||
public CasAuthenticationToken getByTicketId(final String serviceTicket) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a no-op since we are not storing tickets.
|
||||
*/
|
||||
@Override
|
||||
public void putTicketInCache(final CasAuthenticationToken token) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a no-op since we are not storing tickets.
|
||||
*/
|
||||
@Override
|
||||
public void removeTicketFromCache(final CasAuthenticationToken token) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a no-op since we are not storing tickets.
|
||||
*/
|
||||
@Override
|
||||
public void removeTicketFromCache(final String serviceTicket) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Caches tickets using a Spring IoC defined {@link Cache}.
|
||||
*
|
||||
* @author Marten Deinum
|
||||
* @since 3.2
|
||||
*
|
||||
*/
|
||||
public class SpringCacheBasedTicketCache implements StatelessTicketCache {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SpringCacheBasedTicketCache.class);
|
||||
|
||||
private final Cache cache;
|
||||
|
||||
public SpringCacheBasedTicketCache(Cache cache) {
|
||||
Assert.notNull(cache, "cache mandatory");
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CasAuthenticationToken getByTicketId(final String serviceTicket) {
|
||||
final Cache.ValueWrapper element = (serviceTicket != null) ? this.cache.get(serviceTicket) : null;
|
||||
logger.debug(LogMessage.of(() -> "Cache hit: " + (element != null) + "; service ticket: " + serviceTicket));
|
||||
return (element != null) ? (CasAuthenticationToken) element.get() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putTicketInCache(final CasAuthenticationToken token) {
|
||||
String key = token.getCredentials().toString();
|
||||
logger.debug(LogMessage.of(() -> "Cache put: " + key));
|
||||
this.cache.put(key, token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTicketFromCache(final CasAuthenticationToken token) {
|
||||
logger.debug(LogMessage.of(() -> "Cache remove: " + token.getCredentials().toString()));
|
||||
this.removeTicketFromCache(token.getCredentials().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTicketFromCache(final String serviceTicket) {
|
||||
this.cache.evict(serviceTicket);
|
||||
}
|
||||
|
||||
}
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
/**
|
||||
* Caches CAS service tickets and CAS proxy tickets for stateless connections.
|
||||
*
|
||||
* <p>
|
||||
* When a service ticket or proxy ticket is validated against the CAS server, it is unable
|
||||
* to be used again. Most types of callers are stateful and are associated with a given
|
||||
* <code>HttpSession</code>. This allows the affirmative CAS validation outcome to be
|
||||
* stored in the <code>HttpSession</code>, meaning the removal of the ticket from the CAS
|
||||
* server is not an issue.
|
||||
* </p>
|
||||
*
|
||||
* <P>
|
||||
* Stateless callers, such as remoting protocols, cannot take advantage of
|
||||
* <code>HttpSession</code>. If the stateless caller is located a significant network
|
||||
* distance from the CAS server, acquiring a fresh service ticket or proxy ticket for each
|
||||
* invocation would be expensive.
|
||||
* </p>
|
||||
*
|
||||
* <P>
|
||||
* To avoid this issue with stateless callers, it is expected stateless callers will
|
||||
* obtain a single service ticket or proxy ticket, and then present this same ticket to
|
||||
* the Spring Security secured application on each occasion. As no
|
||||
* <code>HttpSession</code> is available for such callers, the affirmative CAS validation
|
||||
* outcome cannot be stored in this location.
|
||||
* </p>
|
||||
*
|
||||
* <P>
|
||||
* The <code>StatelessTicketCache</code> enables the service tickets and proxy tickets
|
||||
* belonging to stateless callers to be placed in a cache. This in-memory cache stores the
|
||||
* <code>CasAuthenticationToken</code>, effectively providing the same capability as a
|
||||
* <code>HttpSession</code> with the ticket identifier being the key rather than a session
|
||||
* identifier.
|
||||
* </p>
|
||||
*
|
||||
* <P>
|
||||
* Implementations should provide a reasonable timeout on stored entries, such that the
|
||||
* stateless caller are not required to unnecessarily acquire fresh CAS service tickets or
|
||||
* proxy tickets.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface StatelessTicketCache {
|
||||
|
||||
/**
|
||||
* Retrieves the <code>CasAuthenticationToken</code> associated with the specified
|
||||
* ticket.
|
||||
*
|
||||
* <P>
|
||||
* If not found, returns a <code>null</code><code>CasAuthenticationToken</code>.
|
||||
* </p>
|
||||
* @return the fully populated authentication token
|
||||
*/
|
||||
CasAuthenticationToken getByTicketId(String serviceTicket);
|
||||
|
||||
/**
|
||||
* Adds the specified <code>CasAuthenticationToken</code> to the cache.
|
||||
*
|
||||
* <P>
|
||||
* The {@link CasAuthenticationToken#getCredentials()} method is used to retrieve the
|
||||
* service ticket number.
|
||||
* </p>
|
||||
* @param token to be added to the cache
|
||||
*/
|
||||
void putTicketInCache(CasAuthenticationToken token);
|
||||
|
||||
/**
|
||||
* Removes the specified ticket from the cache, as per
|
||||
* {@link #removeTicketFromCache(String)}.
|
||||
*
|
||||
* <P>
|
||||
* Implementations should use {@link CasAuthenticationToken#getCredentials()} to
|
||||
* obtain the ticket and then delegate to the {@link #removeTicketFromCache(String)}
|
||||
* method.
|
||||
* </p>
|
||||
* @param token to be removed
|
||||
*/
|
||||
void removeTicketFromCache(CasAuthenticationToken token);
|
||||
|
||||
/**
|
||||
* Removes the specified ticket from the cache, meaning that future calls will require
|
||||
* a new service ticket.
|
||||
*
|
||||
* <P>
|
||||
* This is in case applications wish to provide a session termination capability for
|
||||
* their stateless clients.
|
||||
* </p>
|
||||
* @param serviceTicket to be removed
|
||||
*/
|
||||
void removeTicketFromCache(String serviceTicket);
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An {@code AuthenticationProvider} that can process CAS service tickets and proxy
|
||||
* tickets.
|
||||
*/
|
||||
package org.springframework.security.cas.authentication;
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.jackson2;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import org.apereo.cas.client.authentication.AttributePrincipal;
|
||||
|
||||
/**
|
||||
* Helps in jackson deserialization of class
|
||||
* {@link org.apereo.cas.client.validation.AssertionImpl}, which is used with
|
||||
* {@link org.springframework.security.cas.authentication.CasAuthenticationToken}. To use
|
||||
* this class we need to register with
|
||||
* {@link com.fasterxml.jackson.databind.ObjectMapper}. Type information will be stored
|
||||
* in @class property.
|
||||
* <p>
|
||||
* <pre>
|
||||
* ObjectMapper mapper = new ObjectMapper();
|
||||
* mapper.registerModule(new CasJackson2Module());
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CasJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class AssertionImplMixin {
|
||||
|
||||
/**
|
||||
* Mixin Constructor helps in deserialize
|
||||
* {@link org.apereo.cas.client.validation.AssertionImpl}
|
||||
* @param principal the Principal to associate with the Assertion.
|
||||
* @param validFromDate when the assertion is valid from.
|
||||
* @param validUntilDate when the assertion is valid to.
|
||||
* @param authenticationDate when the assertion is authenticated.
|
||||
* @param attributes the key/value pairs for this attribute.
|
||||
*/
|
||||
@JsonCreator
|
||||
AssertionImplMixin(@JsonProperty("principal") AttributePrincipal principal,
|
||||
@JsonProperty("validFromDate") Date validFromDate, @JsonProperty("validUntilDate") Date validUntilDate,
|
||||
@JsonProperty("authenticationDate") Date authenticationDate,
|
||||
@JsonProperty("attributes") Map<String, Object> attributes) {
|
||||
}
|
||||
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.jackson2;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import org.apereo.cas.client.proxy.ProxyRetriever;
|
||||
|
||||
/**
|
||||
* Helps in deserialize
|
||||
* {@link org.apereo.cas.client.authentication.AttributePrincipalImpl} which is used with
|
||||
* {@link org.springframework.security.cas.authentication.CasAuthenticationToken}. Type
|
||||
* information will be stored in property named @class.
|
||||
* <p>
|
||||
* <pre>
|
||||
* ObjectMapper mapper = new ObjectMapper();
|
||||
* mapper.registerModule(new CasJackson2Module());
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CasJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class AttributePrincipalImplMixin {
|
||||
|
||||
/**
|
||||
* Mixin Constructor helps in deserialize
|
||||
* {@link org.apereo.cas.client.authentication.AttributePrincipalImpl}
|
||||
* @param name the unique identifier for the principal.
|
||||
* @param attributes the key/value pairs for this principal.
|
||||
* @param proxyGrantingTicket the ticket associated with this principal.
|
||||
* @param proxyRetriever the ProxyRetriever implementation to call back to the CAS
|
||||
* server.
|
||||
*/
|
||||
@JsonCreator
|
||||
AttributePrincipalImplMixin(@JsonProperty("name") String name,
|
||||
@JsonProperty("attributes") Map<String, Object> attributes,
|
||||
@JsonProperty("proxyGrantingTicket") String proxyGrantingTicket,
|
||||
@JsonProperty("proxyRetriever") ProxyRetriever proxyRetriever) {
|
||||
}
|
||||
|
||||
}
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.jackson2;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
|
||||
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
|
||||
import org.springframework.security.cas.authentication.CasAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
* Mixin class which helps in deserialize
|
||||
* {@link org.springframework.security.cas.authentication.CasAuthenticationToken} using
|
||||
* jackson. Two more dependent classes needs to register along with this mixin class.
|
||||
* <ol>
|
||||
* <li>{@link org.springframework.security.cas.jackson2.AssertionImplMixin}</li>
|
||||
* <li>{@link org.springframework.security.cas.jackson2.AttributePrincipalImplMixin}</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* <pre>
|
||||
* ObjectMapper mapper = new ObjectMapper();
|
||||
* mapper.registerModule(new CasJackson2Module());
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CasJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
getterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.ANY)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class CasAuthenticationTokenMixin {
|
||||
|
||||
/**
|
||||
* Mixin Constructor helps in deserialize {@link CasAuthenticationToken}
|
||||
* @param keyHash hashCode of provided key to identify if this object made by a given
|
||||
* {@link CasAuthenticationProvider}
|
||||
* @param principal typically the UserDetails object (cannot be <code>null</code>)
|
||||
* @param credentials the service/proxy ticket ID from CAS (cannot be
|
||||
* <code>null</code>)
|
||||
* @param authorities the authorities granted to the user (from the
|
||||
* {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
|
||||
* be <code>null</code>)
|
||||
* @param userDetails the user details (from the
|
||||
* {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
|
||||
* be <code>null</code>)
|
||||
* @param assertion the assertion returned from the CAS servers. It contains the
|
||||
* principal and how to obtain a proxy ticket for the user.
|
||||
*/
|
||||
@JsonCreator
|
||||
CasAuthenticationTokenMixin(@JsonProperty("keyHash") Integer keyHash, @JsonProperty("principal") Object principal,
|
||||
@JsonProperty("credentials") Object credentials,
|
||||
@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities,
|
||||
@JsonProperty("userDetails") UserDetails userDetails, @JsonProperty("assertion") Assertion assertion) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.jackson2;
|
||||
|
||||
import com.fasterxml.jackson.core.Version;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import org.apereo.cas.client.authentication.AttributePrincipalImpl;
|
||||
import org.apereo.cas.client.validation.AssertionImpl;
|
||||
|
||||
import org.springframework.security.cas.authentication.CasAuthenticationToken;
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
|
||||
/**
|
||||
* Jackson module for spring-security-cas. This module register
|
||||
* {@link AssertionImplMixin}, {@link AttributePrincipalImplMixin} and
|
||||
* {@link CasAuthenticationTokenMixin}. If no default typing enabled by default then it'll
|
||||
* enable it because typing info is needed to properly serialize/deserialize objects. In
|
||||
* order to use this module just add this module into your ObjectMapper configuration.
|
||||
*
|
||||
* <pre>
|
||||
* ObjectMapper mapper = new ObjectMapper();
|
||||
* mapper.registerModule(new CasJackson2Module());
|
||||
* </pre> <b>Note: use {@link SecurityJackson2Modules#getModules(ClassLoader)} to get list
|
||||
* of all security modules on the classpath.</b>
|
||||
*
|
||||
* @author Jitendra Singh.
|
||||
* @since 4.2
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
*/
|
||||
public class CasJackson2Module extends SimpleModule {
|
||||
|
||||
public CasJackson2Module() {
|
||||
super(CasJackson2Module.class.getName(), new Version(1, 0, 0, null, null, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupModule(SetupContext context) {
|
||||
SecurityJackson2Modules.enableDefaultTyping(context.getOwner());
|
||||
context.setMixInAnnotations(AssertionImpl.class, AssertionImplMixin.class);
|
||||
context.setMixInAnnotations(AttributePrincipalImpl.class, AttributePrincipalImplMixin.class);
|
||||
context.setMixInAnnotations(CasAuthenticationToken.class, CasAuthenticationTokenMixin.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Spring Security support for Apereo's Central Authentication Service
|
||||
* (<a href="https://github.com/apereo/cas">CAS</a>).
|
||||
*/
|
||||
package org.springframework.security.cas;
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.userdetails;
|
||||
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
|
||||
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
* Abstract class for using the provided CAS assertion to construct a new User object.
|
||||
* This generally is most useful when combined with a SAML-based response from the CAS
|
||||
* Server/client.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class AbstractCasAssertionUserDetailsService
|
||||
implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
|
||||
|
||||
@Override
|
||||
public final UserDetails loadUserDetails(final CasAssertionAuthenticationToken token) {
|
||||
return loadUserDetails(token.getAssertion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected template method for construct a
|
||||
* {@link org.springframework.security.core.userdetails.UserDetails} via the supplied
|
||||
* CAS assertion.
|
||||
* @param assertion the assertion to use to construct the new UserDetails. CANNOT be
|
||||
* NULL.
|
||||
* @return the newly constructed UserDetails.
|
||||
*/
|
||||
protected abstract UserDetails loadUserDetails(Assertion assertion);
|
||||
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.userdetails;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Populates the {@link org.springframework.security.core.GrantedAuthority}s for a user by
|
||||
* reading a list of attributes that were returned as part of the CAS response. Each
|
||||
* attribute is read and each value of the attribute is turned into a GrantedAuthority. If
|
||||
* the attribute has no value then its not added.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class GrantedAuthorityFromAssertionAttributesUserDetailsService
|
||||
extends AbstractCasAssertionUserDetailsService {
|
||||
|
||||
private static final String NON_EXISTENT_PASSWORD_VALUE = "NO_PASSWORD";
|
||||
|
||||
private final String[] attributes;
|
||||
|
||||
private boolean convertToUpperCase = true;
|
||||
|
||||
public GrantedAuthorityFromAssertionAttributesUserDetailsService(final String[] attributes) {
|
||||
Assert.notNull(attributes, "attributes cannot be null.");
|
||||
Assert.isTrue(attributes.length > 0, "At least one attribute is required to retrieve roles from.");
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected UserDetails loadUserDetails(final Assertion assertion) {
|
||||
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
|
||||
for (String attribute : this.attributes) {
|
||||
Object value = assertion.getPrincipal().getAttributes().get(attribute);
|
||||
if (value != null) {
|
||||
if (value instanceof List) {
|
||||
for (Object o : (List<?>) value) {
|
||||
grantedAuthorities.add(createSimpleGrantedAuthority(o));
|
||||
}
|
||||
}
|
||||
else {
|
||||
grantedAuthorities.add(createSimpleGrantedAuthority(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new User(assertion.getPrincipal().getName(), NON_EXISTENT_PASSWORD_VALUE, true, true, true, true,
|
||||
grantedAuthorities);
|
||||
}
|
||||
|
||||
private SimpleGrantedAuthority createSimpleGrantedAuthority(Object o) {
|
||||
return new SimpleGrantedAuthority(this.convertToUpperCase ? o.toString().toUpperCase() : o.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the returned attribute values to uppercase values.
|
||||
* @param convertToUpperCase true if it should convert, false otherwise.
|
||||
*/
|
||||
public void setConvertToUpperCase(final boolean convertToUpperCase) {
|
||||
this.convertToUpperCase = convertToUpperCase;
|
||||
}
|
||||
|
||||
}
|
||||
-151
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apereo.cas.client.util.CommonUtils;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Used by the <code>ExceptionTranslationFilter</code> to commence authentication via the
|
||||
* JA-SIG Central Authentication Service (CAS).
|
||||
* <p>
|
||||
* The user's browser will be redirected to the JA-SIG CAS enterprise-wide login page.
|
||||
* This page is specified by the <code>loginUrl</code> property. Once login is complete,
|
||||
* the CAS login page will redirect to the page indicated by the <code>service</code>
|
||||
* property. The <code>service</code> is a HTTP URL belonging to the current application.
|
||||
* The <code>service</code> URL is monitored by the {@link CasAuthenticationFilter}, which
|
||||
* will validate the CAS login was successful.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Scott Battaglia
|
||||
*/
|
||||
public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, InitializingBean {
|
||||
|
||||
private ServiceProperties serviceProperties;
|
||||
|
||||
private String loginUrl;
|
||||
|
||||
/**
|
||||
* Determines whether the Service URL should include the session id for the specific
|
||||
* user. As of CAS 3.0.5, the session id will automatically be stripped. However,
|
||||
* older versions of CAS (i.e. CAS 2), do not automatically strip the session
|
||||
* identifier (this is a bug on the part of the older server implementations), so an
|
||||
* option to disable the session encoding is provided for backwards compatibility.
|
||||
*
|
||||
* By default, encoding is enabled.
|
||||
*/
|
||||
private boolean encodeServiceUrlWithSessionId = true;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.hasLength(this.loginUrl, "loginUrl must be specified");
|
||||
Assert.notNull(this.serviceProperties, "serviceProperties must be specified");
|
||||
Assert.notNull(this.serviceProperties.getService(), "serviceProperties.getService() cannot be null.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void commence(final HttpServletRequest servletRequest, HttpServletResponse response,
|
||||
AuthenticationException authenticationException) throws IOException {
|
||||
String urlEncodedService = createServiceUrl(servletRequest, response);
|
||||
String redirectUrl = createRedirectUrl(urlEncodedService);
|
||||
preCommence(servletRequest, response);
|
||||
new DefaultRedirectStrategy().sendRedirect(servletRequest, response, redirectUrl);
|
||||
// response.sendRedirect(redirectUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Service Url. The default implementation relies on the CAS client
|
||||
* to do the bulk of the work.
|
||||
* @param request the HttpServletRequest
|
||||
* @param response the HttpServlet Response
|
||||
* @return the constructed service url. CANNOT be NULL.
|
||||
*/
|
||||
protected String createServiceUrl(HttpServletRequest request, HttpServletResponse response) {
|
||||
return CommonUtils.constructServiceUrl(null, response, this.serviceProperties.getService(), null,
|
||||
this.serviceProperties.getArtifactParameter(), this.encodeServiceUrlWithSessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the Url for Redirection to the CAS server. Default implementation relies
|
||||
* on the CAS client to do the bulk of the work.
|
||||
* @param serviceUrl the service url that should be included.
|
||||
* @return the redirect url. CANNOT be NULL.
|
||||
*/
|
||||
protected String createRedirectUrl(String serviceUrl) {
|
||||
return CommonUtils.constructRedirectUrl(this.loginUrl, this.serviceProperties.getServiceParameter(), serviceUrl,
|
||||
this.serviceProperties.isSendRenew(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for you to do your own pre-processing before the redirect occurs.
|
||||
* @param request the HttpServletRequest
|
||||
* @param response the HttpServletResponse
|
||||
*/
|
||||
protected void preCommence(HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The enterprise-wide CAS login URL. Usually something like
|
||||
* <code>https://www.mycompany.com/cas/login</code>.
|
||||
* @return the enterprise-wide CAS login URL
|
||||
*/
|
||||
public final String getLoginUrl() {
|
||||
return this.loginUrl;
|
||||
}
|
||||
|
||||
public final ServiceProperties getServiceProperties() {
|
||||
return this.serviceProperties;
|
||||
}
|
||||
|
||||
public final void setLoginUrl(String loginUrl) {
|
||||
this.loginUrl = loginUrl;
|
||||
}
|
||||
|
||||
public final void setServiceProperties(ServiceProperties serviceProperties) {
|
||||
this.serviceProperties = serviceProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to encode the service url with the session id or not.
|
||||
* @param encodeServiceUrlWithSessionId whether to encode the service url with the
|
||||
* session id or not.
|
||||
*/
|
||||
public final void setEncodeServiceUrlWithSessionId(boolean encodeServiceUrlWithSessionId) {
|
||||
this.encodeServiceUrlWithSessionId = encodeServiceUrlWithSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to encode the service url with the session id or not.
|
||||
* @return whether to encode the service url with the session id or not.
|
||||
*
|
||||
*/
|
||||
protected boolean getEncodeServiceUrlWithSessionId() {
|
||||
return this.encodeServiceUrlWithSessionId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,390 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apereo.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.apereo.cas.client.util.CommonUtils;
|
||||
import org.apereo.cas.client.validation.TicketValidator;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken;
|
||||
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
|
||||
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Processes a CAS service ticket, obtains proxy granting tickets, and processes proxy
|
||||
* tickets.
|
||||
* <h2>Service Tickets</h2>
|
||||
* <p>
|
||||
* A service ticket consists of an opaque ticket string. It arrives at this filter by the
|
||||
* user's browser successfully authenticating using CAS, and then receiving a HTTP
|
||||
* redirect to a <code>service</code>. The opaque ticket string is presented in the
|
||||
* <code>ticket</code> request parameter.
|
||||
* <p>
|
||||
* This filter monitors the <code>service</code> URL so it can receive the service ticket
|
||||
* and process it. By default this filter processes the URL <tt>/login/cas</tt>. When
|
||||
* processing this URL, the value of {@link ServiceProperties#getService()} is used as the
|
||||
* <tt>service</tt> when validating the <code>ticket</code>. This means that it is
|
||||
* important that {@link ServiceProperties#getService()} specifies the same value as the
|
||||
* <tt>filterProcessesUrl</tt>.
|
||||
* <p>
|
||||
* Processing the service ticket involves creating a
|
||||
* <code>CasServiceTicketAuthenticationToken</code> which uses
|
||||
* {@link CasServiceTicketAuthenticationToken#CAS_STATEFUL_IDENTIFIER} for the
|
||||
* <code>principal</code> and the opaque ticket string as the <code>credentials</code>.
|
||||
* <h2>Obtaining Proxy Granting Tickets</h2>
|
||||
* <p>
|
||||
* If specified, the filter can also monitor the <code>proxyReceptorUrl</code>. The filter
|
||||
* will respond to requests matching this url so that the CAS Server can provide a PGT to
|
||||
* the filter. Note that in addition to the <code>proxyReceptorUrl</code> a non-null
|
||||
* <code>proxyGrantingTicketStorage</code> must be provided in order for the filter to
|
||||
* respond to proxy receptor requests. By configuring a shared
|
||||
* {@link ProxyGrantingTicketStorage} between the {@link TicketValidator} and the
|
||||
* CasAuthenticationFilter one can have the CasAuthenticationFilter handle the proxying
|
||||
* requirements for CAS.
|
||||
* <h2>Proxy Tickets</h2>
|
||||
* <p>
|
||||
* The filter can process tickets present on any url. This is useful when wanting to
|
||||
* process proxy tickets. In order for proxy tickets to get processed
|
||||
* {@link ServiceProperties#isAuthenticateAllArtifacts()} must return <code>true</code>.
|
||||
* Additionally, if the request is already authenticated, authentication will <b>not</b>
|
||||
* occur. Last, {@link AuthenticationDetailsSource#buildDetails(Object)} must return a
|
||||
* {@link ServiceAuthenticationDetails}. This can be accomplished using the
|
||||
* {@link ServiceAuthenticationDetailsSource}. In this case
|
||||
* {@link ServiceAuthenticationDetails#getServiceUrl()} will be used for the service url.
|
||||
* <p>
|
||||
* Processing the proxy ticket involves creating a
|
||||
* <code>CasServiceTicketAuthenticationToken</code> which uses
|
||||
* {@link CasServiceTicketAuthenticationToken#CAS_STATELESS_IDENTIFIER} for the
|
||||
* <code>principal</code> and the opaque ticket string as the <code>credentials</code>.
|
||||
* When a proxy ticket is successfully authenticated, the FilterChain continues and the
|
||||
* <code>authenticationSuccessHandler</code> is not used.
|
||||
* <h2>Notes about the <code>AuthenticationManager</code></h2>
|
||||
* <p>
|
||||
* The configured <code>AuthenticationManager</code> is expected to provide a provider
|
||||
* that can recognise <code>CasServiceTicketAuthenticationToken</code>s containing this
|
||||
* special <code>principal</code> name, and process them accordingly by validation with
|
||||
* the CAS server. Additionally, it should be capable of using the result of
|
||||
* {@link ServiceAuthenticationDetails#getServiceUrl()} as the service when validating the
|
||||
* ticket.
|
||||
* <h2>Example Configuration</h2>
|
||||
* <p>
|
||||
* An example configuration that supports service tickets, obtaining proxy granting
|
||||
* tickets, and proxy tickets is illustrated below:
|
||||
*
|
||||
* <pre>
|
||||
* <b:bean id="serviceProperties"
|
||||
* class="org.springframework.security.cas.ServiceProperties"
|
||||
* p:service="https://service.example.com/cas-sample/login/cas"
|
||||
* p:authenticateAllArtifacts="true"/>
|
||||
* <b:bean id="casEntryPoint"
|
||||
* class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"
|
||||
* p:serviceProperties-ref="serviceProperties" p:loginUrl="https://login.example.org/cas/login" />
|
||||
* <b:bean id="casFilter"
|
||||
* class="org.springframework.security.cas.web.CasAuthenticationFilter"
|
||||
* p:authenticationManager-ref="authManager"
|
||||
* p:serviceProperties-ref="serviceProperties"
|
||||
* p:proxyGrantingTicketStorage-ref="pgtStorage"
|
||||
* p:proxyReceptorUrl="/login/cas/proxyreceptor">
|
||||
* <b:property name="authenticationDetailsSource">
|
||||
* <b:bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
|
||||
* </b:property>
|
||||
* <b:property name="authenticationFailureHandler">
|
||||
* <b:bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
|
||||
* p:defaultFailureUrl="/casfailed.jsp"/>
|
||||
* </b:property>
|
||||
* </b:bean>
|
||||
* <!--
|
||||
* NOTE: In a real application you should not use an in memory implementation. You will also want
|
||||
* to ensure to clean up expired tickets by calling ProxyGrantingTicketStorage.cleanup()
|
||||
* -->
|
||||
* <b:bean id="pgtStorage" class="org.apereo.cas.client.proxy.ProxyGrantingTicketStorageImpl"/>
|
||||
* <b:bean id="casAuthProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"
|
||||
* p:serviceProperties-ref="serviceProperties"
|
||||
* p:key="casAuthProviderKey">
|
||||
* <b:property name="authenticationUserDetailsService">
|
||||
* <b:bean
|
||||
* class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
|
||||
* <b:constructor-arg ref="userService" />
|
||||
* </b:bean>
|
||||
* </b:property>
|
||||
* <b:property name="ticketValidator">
|
||||
* <b:bean
|
||||
* class="org.apereo.cas.client.validation.Cas20ProxyTicketValidator"
|
||||
* p:acceptAnyProxy="true"
|
||||
* p:proxyCallbackUrl="https://service.example.com/cas-sample/login/cas/proxyreceptor"
|
||||
* p:proxyGrantingTicketStorage-ref="pgtStorage">
|
||||
* <b:constructor-arg value="https://login.example.org/cas" />
|
||||
* </b:bean>
|
||||
* </b:property>
|
||||
* <b:property name="statelessTicketCache">
|
||||
* <b:bean class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
|
||||
* <b:property name="cache">
|
||||
* <b:bean class="net.sf.ehcache.Cache"
|
||||
* init-method="initialise"
|
||||
* destroy-method="dispose">
|
||||
* <b:constructor-arg value="casTickets"/>
|
||||
* <b:constructor-arg value="50"/>
|
||||
* <b:constructor-arg value="true"/>
|
||||
* <b:constructor-arg value="false"/>
|
||||
* <b:constructor-arg value="3600"/>
|
||||
* <b:constructor-arg value="900"/>
|
||||
* </b:bean>
|
||||
* </b:property>
|
||||
* </b:bean>
|
||||
* </b:property>
|
||||
* </b:bean>
|
||||
* </pre>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
/**
|
||||
* The last portion of the receptor url, i.e. /proxy/receptor
|
||||
*/
|
||||
private RequestMatcher proxyReceptorMatcher;
|
||||
|
||||
/**
|
||||
* The backing storage to store ProxyGrantingTicket requests.
|
||||
*/
|
||||
private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
|
||||
|
||||
private String artifactParameter = ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER;
|
||||
|
||||
private boolean authenticateAllArtifacts;
|
||||
|
||||
private AuthenticationFailureHandler proxyFailureHandler = new SimpleUrlAuthenticationFailureHandler();
|
||||
|
||||
private SecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
|
||||
|
||||
public CasAuthenticationFilter() {
|
||||
super("/login/cas");
|
||||
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
|
||||
setSecurityContextRepository(this.securityContextRepository);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain chain, Authentication authResult) throws IOException, ServletException {
|
||||
boolean continueFilterChain = proxyTicketRequest(serviceTicketRequest(request, response), request);
|
||||
if (!continueFilterChain) {
|
||||
super.successfulAuthentication(request, response, chain, authResult);
|
||||
return;
|
||||
}
|
||||
this.logger.debug(
|
||||
LogMessage.format("Authentication success. Updating SecurityContextHolder to contain: %s", authResult));
|
||||
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
||||
context.setAuthentication(authResult);
|
||||
SecurityContextHolder.setContext(context);
|
||||
this.securityContextRepository.saveContext(context, request, response);
|
||||
if (this.eventPublisher != null) {
|
||||
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException {
|
||||
// if the request is a proxy request process it and return null to indicate the
|
||||
// request has been processed
|
||||
if (proxyReceptorRequest(request)) {
|
||||
this.logger.debug("Responding to proxy receptor request");
|
||||
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
|
||||
return null;
|
||||
}
|
||||
String serviceTicket = obtainArtifact(request);
|
||||
if (serviceTicket == null) {
|
||||
this.logger.debug("Failed to obtain an artifact (cas ticket)");
|
||||
serviceTicket = "";
|
||||
}
|
||||
boolean serviceTicketRequest = serviceTicketRequest(request, response);
|
||||
CasServiceTicketAuthenticationToken authRequest = serviceTicketRequest
|
||||
? CasServiceTicketAuthenticationToken.stateful(serviceTicket)
|
||||
: CasServiceTicketAuthenticationToken.stateless(serviceTicket);
|
||||
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
||||
return this.getAuthenticationManager().authenticate(authRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* If present, gets the artifact (CAS ticket) from the {@link HttpServletRequest}.
|
||||
* @param request
|
||||
* @return if present the artifact from the {@link HttpServletRequest}, else null
|
||||
*/
|
||||
protected String obtainArtifact(HttpServletRequest request) {
|
||||
return request.getParameter(this.artifactParameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to provide proxying capabilities.
|
||||
*/
|
||||
@Override
|
||||
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
|
||||
final boolean serviceTicketRequest = serviceTicketRequest(request, response);
|
||||
final boolean result = serviceTicketRequest || proxyReceptorRequest(request)
|
||||
|| (proxyTicketRequest(serviceTicketRequest, request));
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("requiresAuthentication = " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationFailureHandler} for proxy requests.
|
||||
* @param proxyFailureHandler
|
||||
*/
|
||||
public final void setProxyAuthenticationFailureHandler(AuthenticationFailureHandler proxyFailureHandler) {
|
||||
Assert.notNull(proxyFailureHandler, "proxyFailureHandler cannot be null");
|
||||
this.proxyFailureHandler = proxyFailureHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the {@link AuthenticationFailureHandler} to distinguish between handling
|
||||
* proxy ticket authentication failures and service ticket failures.
|
||||
*/
|
||||
@Override
|
||||
public final void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
|
||||
super.setAuthenticationFailureHandler(new CasAuthenticationFailureHandler(failureHandler));
|
||||
}
|
||||
|
||||
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
|
||||
this.proxyReceptorMatcher = new AntPathRequestMatcher("/**" + proxyReceptorUrl);
|
||||
}
|
||||
|
||||
public final void setProxyGrantingTicketStorage(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
|
||||
this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
|
||||
}
|
||||
|
||||
public final void setServiceProperties(final ServiceProperties serviceProperties) {
|
||||
this.artifactParameter = serviceProperties.getArtifactParameter();
|
||||
this.authenticateAllArtifacts = serviceProperties.isAuthenticateAllArtifacts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the request is elgible to process a service ticket. This method exists
|
||||
* for readability.
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
private boolean serviceTicketRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
boolean result = super.requiresAuthentication(request, response);
|
||||
this.logger.debug(LogMessage.format("serviceTicketRequest = %s", result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the request is elgible to process a proxy ticket.
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private boolean proxyTicketRequest(boolean serviceTicketRequest, HttpServletRequest request) {
|
||||
if (serviceTicketRequest) {
|
||||
return false;
|
||||
}
|
||||
boolean result = this.authenticateAllArtifacts && obtainArtifact(request) != null && !authenticated();
|
||||
this.logger.debug(LogMessage.format("proxyTicketRequest = %s", result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a user is already authenticated.
|
||||
* @return
|
||||
*/
|
||||
private boolean authenticated() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
return authentication != null && authentication.isAuthenticated()
|
||||
&& !(authentication instanceof AnonymousAuthenticationToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the request is elgible to be processed as the proxy receptor.
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private boolean proxyReceptorRequest(HttpServletRequest request) {
|
||||
final boolean result = proxyReceptorConfigured() && this.proxyReceptorMatcher.matches(request);
|
||||
this.logger.debug(LogMessage.format("proxyReceptorRequest = %s", result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the {@link CasAuthenticationFilter} is configured to handle the proxy
|
||||
* receptor requests.
|
||||
* @return
|
||||
*/
|
||||
private boolean proxyReceptorConfigured() {
|
||||
final boolean result = this.proxyGrantingTicketStorage != null && this.proxyReceptorMatcher != null;
|
||||
this.logger.debug(LogMessage.format("proxyReceptorConfigured = %s", result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper for the AuthenticationFailureHandler that will flex the
|
||||
* {@link AuthenticationFailureHandler} that is used. The value
|
||||
* {@link CasAuthenticationFilter#setProxyAuthenticationFailureHandler(AuthenticationFailureHandler)}
|
||||
* will be used for proxy requests that fail. The value
|
||||
* {@link CasAuthenticationFilter#setAuthenticationFailureHandler(AuthenticationFailureHandler)}
|
||||
* will be used for service tickets that fail.
|
||||
*/
|
||||
private class CasAuthenticationFailureHandler implements AuthenticationFailureHandler {
|
||||
|
||||
private final AuthenticationFailureHandler serviceTicketFailureHandler;
|
||||
|
||||
CasAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
|
||||
Assert.notNull(failureHandler, "failureHandler");
|
||||
this.serviceTicketFailureHandler = failureHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException, ServletException {
|
||||
if (serviceTicketRequest(request, response)) {
|
||||
this.serviceTicketFailureHandler.onAuthenticationFailure(request, response, exception);
|
||||
}
|
||||
else {
|
||||
CasAuthenticationFilter.this.proxyFailureHandler.onAuthenticationFailure(request, response, exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-146
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web.authentication;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A default implementation of {@link ServiceAuthenticationDetails} that figures out the
|
||||
* value for {@link #getServiceUrl()} by inspecting the current {@link HttpServletRequest}
|
||||
* and using the current URL minus the artifact and the corresponding value.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
implements ServiceAuthenticationDetails {
|
||||
|
||||
private static final long serialVersionUID = 6192409090610517700L;
|
||||
|
||||
private final String serviceUrl;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param request the current {@link HttpServletRequest} to obtain the
|
||||
* {@link #getServiceUrl()} from.
|
||||
* @param artifactPattern the {@link Pattern} that will be used to clean up the query
|
||||
* string from containing the artifact name and value. This can be created using
|
||||
* {@link #createArtifactPattern(String)}.
|
||||
*/
|
||||
DefaultServiceAuthenticationDetails(String casService, HttpServletRequest request, Pattern artifactPattern)
|
||||
throws MalformedURLException {
|
||||
super(request);
|
||||
URL casServiceUrl = new URL(casService);
|
||||
int port = getServicePort(casServiceUrl);
|
||||
final String query = getQueryString(request, artifactPattern);
|
||||
this.serviceUrl = UrlUtils.buildFullRequestUrl(casServiceUrl.getProtocol(), casServiceUrl.getHost(), port,
|
||||
request.getRequestURI(), query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current URL minus the artifact parameter and its value, if present.
|
||||
* @see org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails#getServiceUrl()
|
||||
*/
|
||||
@Override
|
||||
public String getServiceUrl() {
|
||||
return this.serviceUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails)) {
|
||||
return false;
|
||||
}
|
||||
ServiceAuthenticationDetails that = (ServiceAuthenticationDetails) obj;
|
||||
return this.serviceUrl.equals(that.getServiceUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.serviceUrl.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append(super.toString());
|
||||
result.append("ServiceUrl: ");
|
||||
result.append(this.serviceUrl);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* If present, removes the artifactParameterName and the corresponding value from the
|
||||
* query String.
|
||||
* @param request
|
||||
* @return the query String minus the artifactParameterName and the corresponding
|
||||
* value.
|
||||
*/
|
||||
private String getQueryString(final HttpServletRequest request, final Pattern artifactPattern) {
|
||||
final String query = request.getQueryString();
|
||||
if (query == null) {
|
||||
return null;
|
||||
}
|
||||
String result = artifactPattern.matcher(query).replaceFirst("");
|
||||
if (result.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
// strip off the trailing & only if the artifact was the first query param
|
||||
return result.startsWith("&") ? result.substring(1) : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Pattern} that can be passed into the constructor. This allows the
|
||||
* {@link Pattern} to be reused for every instance of
|
||||
* {@link DefaultServiceAuthenticationDetails}.
|
||||
* @param artifactParameterName
|
||||
* @return
|
||||
*/
|
||||
static Pattern createArtifactPattern(String artifactParameterName) {
|
||||
Assert.hasLength(artifactParameterName, "artifactParameterName is expected to have a length");
|
||||
return Pattern.compile("&?" + Pattern.quote(artifactParameterName) + "=[^&]*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the port from the casServiceURL ensuring to return the proper value if the
|
||||
* default port is being used.
|
||||
* @param casServiceUrl the casServerUrl to be used (i.e.
|
||||
* "https://example.com/context/login/cas")
|
||||
* @return the port that is configured for the casServerUrl
|
||||
*/
|
||||
private static int getServicePort(URL casServiceUrl) {
|
||||
int port = casServiceUrl.getPort();
|
||||
if (port == -1) {
|
||||
port = casServiceUrl.getDefaultPort();
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web.authentication;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* In order for the {@link CasAuthenticationProvider} to provide the correct service url
|
||||
* to authenticate the ticket, the returned value of {@link Authentication#getDetails()}
|
||||
* should implement this interface when tickets can be sent to any URL rather than only
|
||||
* {@link ServiceProperties#getService()}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @see ServiceAuthenticationDetailsSource
|
||||
*/
|
||||
public interface ServiceAuthenticationDetails extends Serializable {
|
||||
|
||||
/**
|
||||
* Gets the absolute service url (i.e. https://example.com/service/).
|
||||
* @return the service url. Cannot be <code>null</code>.
|
||||
*/
|
||||
String getServiceUrl();
|
||||
|
||||
}
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web.authentication;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The {@code AuthenticationDetailsSource} that is set on the
|
||||
* {@code CasAuthenticationFilter} should return a value that implements
|
||||
* {@code ServiceAuthenticationDetails} if the application needs to authenticate dynamic
|
||||
* service urls. The
|
||||
* {@code ServiceAuthenticationDetailsSource#buildDetails(HttpServletRequest)} creates a
|
||||
* default {@code ServiceAuthenticationDetails}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class ServiceAuthenticationDetailsSource
|
||||
implements AuthenticationDetailsSource<HttpServletRequest, ServiceAuthenticationDetails> {
|
||||
|
||||
private final Pattern artifactPattern;
|
||||
|
||||
private ServiceProperties serviceProperties;
|
||||
|
||||
/**
|
||||
* Creates an implementation that uses the specified ServiceProperties and the default
|
||||
* CAS artifactParameterName.
|
||||
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
|
||||
*/
|
||||
public ServiceAuthenticationDetailsSource(ServiceProperties serviceProperties) {
|
||||
this(serviceProperties, ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an implementation that uses the specified artifactParameterName
|
||||
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
|
||||
* @param artifactParameterName the artifactParameterName that is removed from the
|
||||
* current URL. The result becomes the service url. Cannot be null and cannot be an
|
||||
* empty String.
|
||||
*/
|
||||
public ServiceAuthenticationDetailsSource(ServiceProperties serviceProperties, String artifactParameterName) {
|
||||
Assert.notNull(serviceProperties, "serviceProperties cannot be null");
|
||||
this.serviceProperties = serviceProperties;
|
||||
this.artifactPattern = DefaultServiceAuthenticationDetails.createArtifactPattern(artifactParameterName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context the {@code HttpServletRequest} object.
|
||||
* @return the {@code ServiceAuthenticationDetails} containing information about the
|
||||
* current request
|
||||
*/
|
||||
@Override
|
||||
public ServiceAuthenticationDetails buildDetails(HttpServletRequest context) {
|
||||
try {
|
||||
return new DefaultServiceAuthenticationDetails(this.serviceProperties.getService(), context,
|
||||
this.artifactPattern);
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Authentication processing mechanisms which respond to the submission of authentication
|
||||
* credentials using CAS.
|
||||
*/
|
||||
package org.springframework.security.cas.web.authentication;
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Authenticates standard web browser users via CAS.
|
||||
*/
|
||||
package org.springframework.security.cas.web;
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
import org.apereo.cas.client.validation.AssertionImpl;
|
||||
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
/**
|
||||
* @author Scott Battaglia
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractStatelessTicketCacheTests {
|
||||
|
||||
protected CasAuthenticationToken getToken() {
|
||||
List<String> proxyList = new ArrayList<>();
|
||||
proxyList.add("https://localhost/newPortal/login/cas");
|
||||
User user = new User("rod", "password", true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"));
|
||||
final Assertion assertion = new AssertionImpl("rod");
|
||||
return new CasAuthenticationToken("key", user, "ST-0-ER94xMJmn6pha35CQRoZ",
|
||||
AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"), user, assertion);
|
||||
}
|
||||
|
||||
}
|
||||
-376
@@ -1,376 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
import org.apereo.cas.client.validation.AssertionImpl;
|
||||
import org.apereo.cas.client.validation.TicketValidator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
|
||||
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;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests {@link CasAuthenticationProvider}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Scott Battaglia
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CasAuthenticationProviderTests {
|
||||
|
||||
private UserDetails makeUserDetails() {
|
||||
return new User("user", "password", true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"));
|
||||
}
|
||||
|
||||
private UserDetails makeUserDetailsFromAuthoritiesPopulator() {
|
||||
return new User("user", "password", true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B"));
|
||||
}
|
||||
|
||||
private ServiceProperties makeServiceProperties() {
|
||||
final ServiceProperties serviceProperties = new ServiceProperties();
|
||||
serviceProperties.setSendRenew(false);
|
||||
serviceProperties.setService("http://test.com");
|
||||
return serviceProperties;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void statefulAuthenticationIsSuccessful() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
StatelessTicketCache cache = new MockStatelessTicketCache();
|
||||
cap.setStatelessTicketCache(cache);
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.afterPropertiesSet();
|
||||
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateful("ST-123");
|
||||
token.setDetails("details");
|
||||
Authentication result = cap.authenticate(token);
|
||||
// Confirm ST-123 was NOT added to the cache
|
||||
assertThat(cache.getByTicketId("ST-456") == null).isTrue();
|
||||
if (!(result instanceof CasAuthenticationToken)) {
|
||||
fail("Should have returned a CasAuthenticationToken");
|
||||
}
|
||||
CasAuthenticationToken casResult = (CasAuthenticationToken) result;
|
||||
assertThat(casResult.getPrincipal()).isEqualTo(makeUserDetailsFromAuthoritiesPopulator());
|
||||
assertThat(casResult.getCredentials()).isEqualTo("ST-123");
|
||||
assertThat(casResult.getAuthorities()).contains(new SimpleGrantedAuthority("ROLE_A"));
|
||||
assertThat(casResult.getAuthorities()).contains(new SimpleGrantedAuthority("ROLE_B"));
|
||||
assertThat(casResult.getKeyHash()).isEqualTo(cap.getKey().hashCode());
|
||||
assertThat(casResult.getDetails()).isEqualTo("details");
|
||||
// Now confirm the CasAuthenticationToken is automatically re-accepted.
|
||||
// To ensure TicketValidator not called again, set it to deliver an exception...
|
||||
cap.setTicketValidator(new MockTicketValidator(false));
|
||||
Authentication laterResult = cap.authenticate(result);
|
||||
assertThat(laterResult).isEqualTo(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void statelessAuthenticationIsSuccessful() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
StatelessTicketCache cache = new MockStatelessTicketCache();
|
||||
cap.setStatelessTicketCache(cache);
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless("ST-456");
|
||||
token.setDetails("details");
|
||||
Authentication result = cap.authenticate(token);
|
||||
// Confirm ST-456 was added to the cache
|
||||
assertThat(cache.getByTicketId("ST-456") != null).isTrue();
|
||||
if (!(result instanceof CasAuthenticationToken)) {
|
||||
fail("Should have returned a CasAuthenticationToken");
|
||||
}
|
||||
assertThat(result.getPrincipal()).isEqualTo(makeUserDetailsFromAuthoritiesPopulator());
|
||||
assertThat(result.getCredentials()).isEqualTo("ST-456");
|
||||
assertThat(result.getDetails()).isEqualTo("details");
|
||||
// Now try to authenticate again. To ensure TicketValidator not
|
||||
// called again, set it to deliver an exception...
|
||||
cap.setTicketValidator(new MockTicketValidator(false));
|
||||
// Previously created CasServiceTicketAuthenticationToken is OK
|
||||
Authentication newResult = cap.authenticate(token);
|
||||
assertThat(newResult.getPrincipal()).isEqualTo(makeUserDetailsFromAuthoritiesPopulator());
|
||||
assertThat(newResult.getCredentials()).isEqualTo("ST-456");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateAllNullService() throws Exception {
|
||||
String serviceUrl = "https://service/context";
|
||||
ServiceAuthenticationDetails details = mock(ServiceAuthenticationDetails.class);
|
||||
given(details.getServiceUrl()).willReturn(serviceUrl);
|
||||
TicketValidator validator = mock(TicketValidator.class);
|
||||
given(validator.validate(any(String.class), any(String.class))).willReturn(new AssertionImpl("rod"));
|
||||
ServiceProperties serviceProperties = makeServiceProperties();
|
||||
serviceProperties.setAuthenticateAllArtifacts(true);
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
cap.setTicketValidator(validator);
|
||||
cap.setServiceProperties(serviceProperties);
|
||||
cap.afterPropertiesSet();
|
||||
String ticket = "ST-456";
|
||||
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless(ticket);
|
||||
Authentication result = cap.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateAllAuthenticationIsSuccessful() throws Exception {
|
||||
String serviceUrl = "https://service/context";
|
||||
ServiceAuthenticationDetails details = mock(ServiceAuthenticationDetails.class);
|
||||
given(details.getServiceUrl()).willReturn(serviceUrl);
|
||||
TicketValidator validator = mock(TicketValidator.class);
|
||||
given(validator.validate(any(String.class), any(String.class))).willReturn(new AssertionImpl("rod"));
|
||||
ServiceProperties serviceProperties = makeServiceProperties();
|
||||
serviceProperties.setAuthenticateAllArtifacts(true);
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
cap.setTicketValidator(validator);
|
||||
cap.setServiceProperties(serviceProperties);
|
||||
cap.afterPropertiesSet();
|
||||
String ticket = "ST-456";
|
||||
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless(ticket);
|
||||
Authentication result = cap.authenticate(token);
|
||||
verify(validator).validate(ticket, serviceProperties.getService());
|
||||
serviceProperties.setAuthenticateAllArtifacts(true);
|
||||
result = cap.authenticate(token);
|
||||
verify(validator, times(2)).validate(ticket, serviceProperties.getService());
|
||||
token.setDetails(details);
|
||||
result = cap.authenticate(token);
|
||||
verify(validator).validate(ticket, serviceUrl);
|
||||
serviceProperties.setAuthenticateAllArtifacts(false);
|
||||
serviceProperties.setService(null);
|
||||
cap.setServiceProperties(serviceProperties);
|
||||
cap.afterPropertiesSet();
|
||||
result = cap.authenticate(token);
|
||||
verify(validator, times(2)).validate(ticket, serviceUrl);
|
||||
token.setDetails(new WebAuthenticationDetails(new MockHttpServletRequest()));
|
||||
assertThatIllegalStateException().isThrownBy(() -> cap.authenticate(token));
|
||||
cap.setServiceProperties(null);
|
||||
cap.afterPropertiesSet();
|
||||
assertThatIllegalStateException().isThrownBy(() -> cap.authenticate(token));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingTicketIdIsDetected() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
StatelessTicketCache cache = new MockStatelessTicketCache();
|
||||
cap.setStatelessTicketCache(cache);
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateful("");
|
||||
assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> cap.authenticate(token));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidKeyIsDetected() throws Exception {
|
||||
final Assertion assertion = new AssertionImpl("test");
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
StatelessTicketCache cache = new MockStatelessTicketCache();
|
||||
cap.setStatelessTicketCache(cache);
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
CasAuthenticationToken token = new CasAuthenticationToken("WRONG_KEY", makeUserDetails(), "credentials",
|
||||
AuthorityUtils.createAuthorityList("XX"), makeUserDetails(), assertion);
|
||||
assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> cap.authenticate(token));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsMissingAuthoritiesPopulator() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setKey("qwerty");
|
||||
cap.setStatelessTicketCache(new MockStatelessTicketCache());
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> cap.afterPropertiesSet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsMissingKey() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setStatelessTicketCache(new MockStatelessTicketCache());
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> cap.afterPropertiesSet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsMissingStatelessTicketCache() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
// set this explicitly to null to test failure
|
||||
cap.setStatelessTicketCache(null);
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> cap.afterPropertiesSet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsMissingTicketValidator() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
cap.setStatelessTicketCache(new MockStatelessTicketCache());
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> cap.afterPropertiesSet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gettersAndSettersMatch() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
cap.setStatelessTicketCache(new MockStatelessTicketCache());
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
// TODO disabled because why do we need to expose this?
|
||||
// assertThat(cap.getUserDetailsService() != null).isTrue();
|
||||
assertThat(cap.getKey()).isEqualTo("qwerty");
|
||||
assertThat(cap.getStatelessTicketCache() != null).isTrue();
|
||||
assertThat(cap.getTicketValidator() != null).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresClassesItDoesNotSupport() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
cap.setStatelessTicketCache(new MockStatelessTicketCache());
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("user", "password", "ROLE_A");
|
||||
assertThat(cap.supports(TestingAuthenticationToken.class)).isFalse();
|
||||
// Try it anyway
|
||||
assertThat(cap.authenticate(token)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresUsernamePasswordAuthenticationTokensWithoutCasIdentifiersAsPrincipal() throws Exception {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
|
||||
cap.setKey("qwerty");
|
||||
cap.setStatelessTicketCache(new MockStatelessTicketCache());
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("some_normal_user",
|
||||
"password", AuthorityUtils.createAuthorityList("ROLE_A"));
|
||||
assertThat(cap.authenticate(token)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsRequiredTokens() {
|
||||
CasAuthenticationProvider cap = new CasAuthenticationProvider();
|
||||
assertThat(cap.supports(CasServiceTicketAuthenticationToken.class)).isTrue();
|
||||
assertThat(cap.supports(CasAuthenticationToken.class)).isTrue();
|
||||
}
|
||||
|
||||
private class MockAuthoritiesPopulator implements AuthenticationUserDetailsService {
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserDetails(final Authentication token) throws UsernameNotFoundException {
|
||||
return makeUserDetailsFromAuthoritiesPopulator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class MockStatelessTicketCache implements StatelessTicketCache {
|
||||
|
||||
private Map<String, CasAuthenticationToken> cache = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public CasAuthenticationToken getByTicketId(String serviceTicket) {
|
||||
return this.cache.get(serviceTicket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putTicketInCache(CasAuthenticationToken token) {
|
||||
this.cache.put(token.getCredentials().toString(), token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTicketFromCache(CasAuthenticationToken token) {
|
||||
throw new UnsupportedOperationException("mock method not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTicketFromCache(String serviceTicket) {
|
||||
throw new UnsupportedOperationException("mock method not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class MockTicketValidator implements TicketValidator {
|
||||
|
||||
private boolean returnTicket;
|
||||
|
||||
MockTicketValidator(boolean returnTicket) {
|
||||
this.returnTicket = returnTicket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Assertion validate(final String ticket, final String service) {
|
||||
if (this.returnTicket) {
|
||||
return new AssertionImpl("rod");
|
||||
}
|
||||
throw new BadCredentialsException("As requested from mock");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
import org.apereo.cas.client.validation.AssertionImpl;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests {@link CasAuthenticationToken}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class CasAuthenticationTokenTests {
|
||||
|
||||
private final List<GrantedAuthority> ROLES = AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO");
|
||||
|
||||
private UserDetails makeUserDetails() {
|
||||
return makeUserDetails("user");
|
||||
}
|
||||
|
||||
private UserDetails makeUserDetails(final String name) {
|
||||
return new User(name, "password", true, true, true, true, this.ROLES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorRejectsNulls() {
|
||||
Assertion assertion = new AssertionImpl("test");
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CasAuthenticationToken(null, makeUserDetails(),
|
||||
"Password", this.ROLES, makeUserDetails(), assertion));
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> new CasAuthenticationToken("key", null, "Password", this.ROLES, makeUserDetails(), assertion));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CasAuthenticationToken("key", makeUserDetails(), null,
|
||||
this.ROLES, makeUserDetails(), assertion));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CasAuthenticationToken("key", makeUserDetails(),
|
||||
"Password", this.ROLES, makeUserDetails(), null));
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES, null, assertion));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CasAuthenticationToken("key", makeUserDetails(),
|
||||
"Password", AuthorityUtils.createAuthorityList("ROLE_1", null), makeUserDetails(), assertion));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenEmptyKeyThenThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> new CasAuthenticationToken("", "user", "password", Collections.<GrantedAuthority>emptyList(),
|
||||
new User("user", "password", Collections.<GrantedAuthority>emptyList()), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsWhenEqual() {
|
||||
final Assertion assertion = new AssertionImpl("test");
|
||||
CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion);
|
||||
CasAuthenticationToken token2 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion);
|
||||
assertThat(token2).isEqualTo(token1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetters() {
|
||||
// Build the proxy list returned in the ticket from CAS
|
||||
final Assertion assertion = new AssertionImpl("test");
|
||||
CasAuthenticationToken token = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion);
|
||||
assertThat(token.getKeyHash()).isEqualTo("key".hashCode());
|
||||
assertThat(token.getPrincipal()).isEqualTo(makeUserDetails());
|
||||
assertThat(token.getCredentials()).isEqualTo("Password");
|
||||
assertThat(token.getAuthorities()).contains(new SimpleGrantedAuthority("ROLE_ONE"));
|
||||
assertThat(token.getAuthorities()).contains(new SimpleGrantedAuthority("ROLE_TWO"));
|
||||
assertThat(token.getAssertion()).isEqualTo(assertion);
|
||||
assertThat(token.getUserDetails().getUsername()).isEqualTo(makeUserDetails().getUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoArgConstructorDoesntExist() {
|
||||
assertThatExceptionOfType(NoSuchMethodException.class)
|
||||
.isThrownBy(() -> CasAuthenticationToken.class.getDeclaredConstructor((Class[]) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEqualsDueToAbstractParentEqualsCheck() {
|
||||
final Assertion assertion = new AssertionImpl("test");
|
||||
CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion);
|
||||
CasAuthenticationToken token2 = new CasAuthenticationToken("key", makeUserDetails("OTHER_NAME"), "Password",
|
||||
this.ROLES, makeUserDetails(), assertion);
|
||||
assertThat(!token1.equals(token2)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEqualsDueToKey() {
|
||||
final Assertion assertion = new AssertionImpl("test");
|
||||
CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion);
|
||||
CasAuthenticationToken token2 = new CasAuthenticationToken("DIFFERENT_KEY", makeUserDetails(), "Password",
|
||||
this.ROLES, makeUserDetails(), assertion);
|
||||
assertThat(!token1.equals(token2)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEqualsDueToAssertion() {
|
||||
final Assertion assertion = new AssertionImpl("test");
|
||||
final Assertion assertion2 = new AssertionImpl("test");
|
||||
CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion);
|
||||
CasAuthenticationToken token2 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion2);
|
||||
assertThat(!token1.equals(token2)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAuthenticated() {
|
||||
final Assertion assertion = new AssertionImpl("test");
|
||||
CasAuthenticationToken token = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion);
|
||||
assertThat(token.isAuthenticated()).isTrue();
|
||||
token.setAuthenticated(false);
|
||||
assertThat(!token.isAuthenticated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
final Assertion assertion = new AssertionImpl("test");
|
||||
CasAuthenticationToken token = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion);
|
||||
String result = token.toString();
|
||||
assertThat(result.lastIndexOf("Credentials (Service/Proxy Ticket):") != -1).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test cases for the @link {@link NullStatelessTicketCache}
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
*
|
||||
*/
|
||||
public class NullStatelessTicketCacheTests extends AbstractStatelessTicketCacheTests {
|
||||
|
||||
private StatelessTicketCache cache = new NullStatelessTicketCache();
|
||||
|
||||
@Test
|
||||
public void testGetter() {
|
||||
assertThat(this.cache.getByTicketId(null)).isNull();
|
||||
assertThat(this.cache.getByTicketId("test")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertAndGet() {
|
||||
final CasAuthenticationToken token = getToken();
|
||||
this.cache.putTicketInCache(token);
|
||||
assertThat(this.cache.getByTicketId((String) token.getCredentials())).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests
|
||||
* {@link org.springframework.security.cas.authentication.SpringCacheBasedTicketCache}.
|
||||
*
|
||||
* @author Marten Deinum
|
||||
* @since 3.2
|
||||
*/
|
||||
public class SpringCacheBasedTicketCacheTests extends AbstractStatelessTicketCacheTests {
|
||||
|
||||
private static CacheManager cacheManager;
|
||||
|
||||
@BeforeAll
|
||||
public static void initCacheManaer() {
|
||||
cacheManager = new ConcurrentMapCacheManager();
|
||||
cacheManager.getCache("castickets");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheOperation() throws Exception {
|
||||
SpringCacheBasedTicketCache cache = new SpringCacheBasedTicketCache(cacheManager.getCache("castickets"));
|
||||
final CasAuthenticationToken token = getToken();
|
||||
// Check it gets stored in the cache
|
||||
cache.putTicketInCache(token);
|
||||
assertThat(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ")).isEqualTo(token);
|
||||
// Check it gets removed from the cache
|
||||
cache.removeTicketFromCache(getToken());
|
||||
assertThat(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ")).isNull();
|
||||
// Check it doesn't return values for null or unknown service tickets
|
||||
assertThat(cache.getByTicketId(null)).isNull();
|
||||
assertThat(cache.getByTicketId("UNKNOWN_SERVICE_TICKET")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartupDetectsMissingCache() throws Exception {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new SpringCacheBasedTicketCache(null));
|
||||
}
|
||||
|
||||
}
|
||||
-154
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.jackson2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apereo.cas.client.authentication.AttributePrincipalImpl;
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
import org.apereo.cas.client.validation.AssertionImpl;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
|
||||
import org.springframework.security.cas.authentication.CasAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
*/
|
||||
public class CasAuthenticationTokenMixinTests {
|
||||
|
||||
private static final String KEY = "casKey";
|
||||
|
||||
private static final String PASSWORD = "\"1234\"";
|
||||
|
||||
private static final Date START_DATE = new Date();
|
||||
|
||||
private static final Date END_DATE = new Date();
|
||||
|
||||
public static final String AUTHORITY_JSON = "{\"@class\": \"org.springframework.security.core.authority.SimpleGrantedAuthority\", \"authority\": \"ROLE_USER\"}";
|
||||
|
||||
public static final String AUTHORITIES_SET_JSON = "[\"java.util.Collections$UnmodifiableSet\", [" + AUTHORITY_JSON
|
||||
+ "]]";
|
||||
|
||||
public static final String AUTHORITIES_ARRAYLIST_JSON = "[\"java.util.Collections$UnmodifiableRandomAccessList\", ["
|
||||
+ AUTHORITY_JSON + "]]";
|
||||
|
||||
// @formatter:off
|
||||
public static final String USER_JSON = "{"
|
||||
+ "\"@class\": \"org.springframework.security.core.userdetails.User\", "
|
||||
+ "\"username\": \"admin\","
|
||||
+ " \"password\": " + PASSWORD + ", "
|
||||
+ "\"accountNonExpired\": true, "
|
||||
+ "\"accountNonLocked\": true, "
|
||||
+ "\"credentialsNonExpired\": true, "
|
||||
+ "\"enabled\": true, "
|
||||
+ "\"authorities\": " + AUTHORITIES_SET_JSON
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
private static final String CAS_TOKEN_JSON = "{"
|
||||
+ "\"@class\": \"org.springframework.security.cas.authentication.CasAuthenticationToken\", "
|
||||
+ "\"keyHash\": " + KEY.hashCode() + "," + "\"principal\": " + USER_JSON + ", " + "\"credentials\": "
|
||||
+ PASSWORD + ", " + "\"authorities\": " + AUTHORITIES_ARRAYLIST_JSON + "," + "\"userDetails\": " + USER_JSON
|
||||
+ "," + "\"authenticated\": true, " + "\"details\": null," + "\"assertion\": {"
|
||||
+ "\"@class\": \"org.apereo.cas.client.validation.AssertionImpl\", " + "\"principal\": {"
|
||||
+ "\"@class\": \"org.apereo.cas.client.authentication.AttributePrincipalImpl\", "
|
||||
+ "\"name\": \"assertName\", " + "\"attributes\": {\"@class\": \"java.util.Collections$EmptyMap\"}, "
|
||||
+ "\"proxyGrantingTicket\": null, " + "\"proxyRetriever\": null" + "}, "
|
||||
+ "\"validFromDate\": [\"java.util.Date\", " + START_DATE.getTime() + "], "
|
||||
+ "\"validUntilDate\": [\"java.util.Date\", " + END_DATE.getTime() + "],"
|
||||
+ "\"authenticationDate\": [\"java.util.Date\", " + START_DATE.getTime() + "], "
|
||||
+ "\"attributes\": {\"@class\": \"java.util.Collections$EmptyMap\"},"
|
||||
+ "\"context\": {\"@class\":\"java.util.HashMap\"}" + "}" + "}";
|
||||
|
||||
private static final String CAS_TOKEN_CLEARED_JSON = CAS_TOKEN_JSON.replaceFirst(PASSWORD, "null");
|
||||
|
||||
protected ObjectMapper mapper;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.mapper = new ObjectMapper();
|
||||
ClassLoader loader = getClass().getClassLoader();
|
||||
this.mapper.registerModules(SecurityJackson2Modules.getModules(loader));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializeCasAuthenticationTest() throws JsonProcessingException, JSONException {
|
||||
CasAuthenticationToken token = createCasAuthenticationToken();
|
||||
String actualJson = this.mapper.writeValueAsString(token);
|
||||
JSONAssert.assertEquals(CAS_TOKEN_JSON, actualJson, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializeCasAuthenticationTestAfterEraseCredentialInvoked()
|
||||
throws JsonProcessingException, JSONException {
|
||||
CasAuthenticationToken token = createCasAuthenticationToken();
|
||||
token.eraseCredentials();
|
||||
String actualJson = this.mapper.writeValueAsString(token);
|
||||
JSONAssert.assertEquals(CAS_TOKEN_CLEARED_JSON, actualJson, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializeCasAuthenticationTestAfterEraseCredentialInvoked() throws Exception {
|
||||
CasAuthenticationToken token = this.mapper.readValue(CAS_TOKEN_CLEARED_JSON, CasAuthenticationToken.class);
|
||||
assertThat(((UserDetails) token.getPrincipal()).getPassword()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializeCasAuthenticationTest() throws IOException {
|
||||
CasAuthenticationToken token = this.mapper.readValue(CAS_TOKEN_JSON, CasAuthenticationToken.class);
|
||||
assertThat(token).isNotNull();
|
||||
assertThat(token.getPrincipal()).isNotNull().isInstanceOf(User.class);
|
||||
assertThat(((User) token.getPrincipal()).getUsername()).isEqualTo("admin");
|
||||
assertThat(((User) token.getPrincipal()).getPassword()).isEqualTo("1234");
|
||||
assertThat(token.getUserDetails()).isNotNull().isInstanceOf(User.class);
|
||||
assertThat(token.getAssertion()).isNotNull().isInstanceOf(AssertionImpl.class);
|
||||
assertThat(token.getKeyHash()).isEqualTo(KEY.hashCode());
|
||||
assertThat(token.getUserDetails().getAuthorities()).extracting(GrantedAuthority::getAuthority)
|
||||
.containsOnly("ROLE_USER");
|
||||
assertThat(token.getAssertion().getAuthenticationDate()).isEqualTo(START_DATE);
|
||||
assertThat(token.getAssertion().getValidFromDate()).isEqualTo(START_DATE);
|
||||
assertThat(token.getAssertion().getValidUntilDate()).isEqualTo(END_DATE);
|
||||
assertThat(token.getAssertion().getPrincipal().getName()).isEqualTo("assertName");
|
||||
assertThat(token.getAssertion().getAttributes()).hasSize(0);
|
||||
}
|
||||
|
||||
private CasAuthenticationToken createCasAuthenticationToken() {
|
||||
User principal = new User("admin", "1234", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
|
||||
Collection<? extends GrantedAuthority> authorities = Collections
|
||||
.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
|
||||
Assertion assertion = new AssertionImpl(new AttributePrincipalImpl("assertName"), START_DATE, END_DATE,
|
||||
START_DATE, Collections.<String, Object>emptyMap());
|
||||
return new CasAuthenticationToken(KEY, principal, principal.getPassword(), authorities,
|
||||
new User("admin", "1234", authorities), assertion);
|
||||
}
|
||||
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.userdetails;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apereo.cas.client.authentication.AttributePrincipal;
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class GrantedAuthorityFromAssertionAttributesUserDetailsServiceTests {
|
||||
|
||||
@Test
|
||||
public void correctlyExtractsNamedAttributesFromAssertionAndConvertsThemToAuthorities() {
|
||||
GrantedAuthorityFromAssertionAttributesUserDetailsService uds = new GrantedAuthorityFromAssertionAttributesUserDetailsService(
|
||||
new String[] { "a", "b", "c", "d" });
|
||||
uds.setConvertToUpperCase(false);
|
||||
Assertion assertion = mock(Assertion.class);
|
||||
AttributePrincipal principal = mock(AttributePrincipal.class);
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put("a", Arrays.asList("role_a1", "role_a2"));
|
||||
attributes.put("b", "role_b");
|
||||
attributes.put("c", "role_c");
|
||||
attributes.put("d", null);
|
||||
attributes.put("someother", "unused");
|
||||
given(assertion.getPrincipal()).willReturn(principal);
|
||||
given(principal.getAttributes()).willReturn(attributes);
|
||||
given(principal.getName()).willReturn("somebody");
|
||||
CasAssertionAuthenticationToken token = new CasAssertionAuthenticationToken(assertion, "ticket");
|
||||
UserDetails user = uds.loadUserDetails(token);
|
||||
Set<String> roles = AuthorityUtils.authorityListToSet(user.getAuthorities());
|
||||
assertThat(roles).containsExactlyInAnyOrder("role_a1", "role_a2", "role_b", "role_c");
|
||||
}
|
||||
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests {@link CasAuthenticationEntryPoint}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class CasAuthenticationEntryPointTests {
|
||||
|
||||
@Test
|
||||
public void testDetectsMissingLoginFormUrl() throws Exception {
|
||||
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
|
||||
ep.setServiceProperties(new ServiceProperties());
|
||||
assertThatIllegalArgumentException().isThrownBy(ep::afterPropertiesSet)
|
||||
.withMessage("loginUrl must be specified");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectsMissingServiceProperties() throws Exception {
|
||||
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
|
||||
ep.setLoginUrl("https://cas/login");
|
||||
assertThatIllegalArgumentException().isThrownBy(ep::afterPropertiesSet)
|
||||
.withMessage("serviceProperties must be specified");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGettersSetters() {
|
||||
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
|
||||
ep.setLoginUrl("https://cas/login");
|
||||
assertThat(ep.getLoginUrl()).isEqualTo("https://cas/login");
|
||||
ep.setServiceProperties(new ServiceProperties());
|
||||
assertThat(ep.getServiceProperties() != null).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalOperationWithRenewFalse() throws Exception {
|
||||
ServiceProperties sp = new ServiceProperties();
|
||||
sp.setSendRenew(false);
|
||||
sp.setService("https://mycompany.com/bigWebApp/login/cas");
|
||||
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
|
||||
ep.setLoginUrl("https://cas/login");
|
||||
ep.setServiceProperties(sp);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("/some_path");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
ep.afterPropertiesSet();
|
||||
ep.commence(request, response, null);
|
||||
assertThat(
|
||||
"https://cas/login?service=" + URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8"))
|
||||
.isEqualTo(response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalOperationWithRenewTrue() throws Exception {
|
||||
ServiceProperties sp = new ServiceProperties();
|
||||
sp.setSendRenew(true);
|
||||
sp.setService("https://mycompany.com/bigWebApp/login/cas");
|
||||
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
|
||||
ep.setLoginUrl("https://cas/login");
|
||||
ep.setServiceProperties(sp);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("/some_path");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
ep.afterPropertiesSet();
|
||||
ep.commence(request, response, null);
|
||||
assertThat("https://cas/login?service="
|
||||
+ URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8") + "&renew=true")
|
||||
.isEqualTo(response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
}
|
||||
-221
@@ -1,221 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import org.apereo.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Tests {@link CasAuthenticationFilter}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class CasAuthenticationFilterTests {
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGettersSetters() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl("/someurl");
|
||||
filter.setServiceProperties(new ServiceProperties());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalOperation() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/login/cas");
|
||||
request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setAuthenticationManager((a) -> a);
|
||||
assertThat(filter.requiresAuthentication(request, new MockHttpServletResponse())).isTrue();
|
||||
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
assertThat(result != null).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullServiceTicketHandledGracefully() throws Exception {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setAuthenticationManager((a) -> {
|
||||
throw new BadCredentialsException("Rejected");
|
||||
});
|
||||
assertThatExceptionOfType(AuthenticationException.class).isThrownBy(
|
||||
() -> filter.attemptAuthentication(new MockHttpServletRequest(), new MockHttpServletResponse()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthenticationFilterProcessUrl() {
|
||||
String url = "/login/cas";
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setFilterProcessesUrl(url);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setServletPath(url);
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthenticationProxyRequest() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setServletPath("/pgtCallback");
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
filter.setProxyReceptorUrl(request.getServletPath());
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
request.setServletPath("/other");
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthenticationAuthAll() {
|
||||
ServiceProperties properties = new ServiceProperties();
|
||||
properties.setAuthenticateAllArtifacts(true);
|
||||
String url = "/login/cas";
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setFilterProcessesUrl(url);
|
||||
filter.setServiceProperties(properties);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setServletPath(url);
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
request.setServletPath("/other");
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
request.setParameter(properties.getArtifactParameter(), "value");
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
SecurityContextHolder.getContext().setAuthentication(new AnonymousAuthenticationToken("key", "principal",
|
||||
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")));
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("un", "principal"));
|
||||
assertThat(filter.requiresAuthentication(request, response)).isTrue();
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new TestingAuthenticationToken("un", "principal", "ROLE_ANONYMOUS"));
|
||||
assertThat(filter.requiresAuthentication(request, response)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateProxyUrl() throws Exception {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setServletPath("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getServletPath());
|
||||
assertThat(filter.attemptAuthentication(request, response)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoFilterAuthenticateAll() throws Exception {
|
||||
AuthenticationSuccessHandler successHandler = mock(AuthenticationSuccessHandler.class);
|
||||
AuthenticationManager manager = mock(AuthenticationManager.class);
|
||||
Authentication authentication = new TestingAuthenticationToken("un", "pwd", "ROLE_USER");
|
||||
given(manager.authenticate(any(Authentication.class))).willReturn(authentication);
|
||||
ServiceProperties serviceProperties = new ServiceProperties();
|
||||
serviceProperties.setAuthenticateAllArtifacts(true);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setParameter("ticket", "ST-1-123");
|
||||
request.setServletPath("/authenticate");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setServiceProperties(serviceProperties);
|
||||
filter.setAuthenticationSuccessHandler(successHandler);
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setAuthenticationManager(manager);
|
||||
filter.afterPropertiesSet();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull()
|
||||
.withFailMessage("Authentication should not be null");
|
||||
verify(chain).doFilter(request, response);
|
||||
verifyNoInteractions(successHandler);
|
||||
// validate for when the filterProcessUrl matches
|
||||
filter.setFilterProcessesUrl(request.getServletPath());
|
||||
SecurityContextHolder.clearContext();
|
||||
filter.doFilter(request, response, chain);
|
||||
verifyNoMoreInteractions(chain);
|
||||
verify(successHandler).onAuthenticationSuccess(request, response, authentication);
|
||||
}
|
||||
|
||||
// SEC-1592
|
||||
@Test
|
||||
public void testChainNotInvokedForProxyReceptor() throws Exception {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
request.setServletPath("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getServletPath());
|
||||
filter.doFilter(request, response, chain);
|
||||
verifyNoInteractions(chain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successfulAuthenticationWhenProxyRequestThenSavesSecurityContext() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setParameter(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER, "ticket");
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
ServiceProperties serviceProperties = new ServiceProperties();
|
||||
serviceProperties.setAuthenticateAllArtifacts(true);
|
||||
filter.setServiceProperties(serviceProperties);
|
||||
|
||||
SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class);
|
||||
ReflectionTestUtils.setField(filter, "securityContextRepository", securityContextRepository);
|
||||
|
||||
filter.successfulAuthentication(request, response, new MockFilterChain(), mock(Authentication.class));
|
||||
verify(securityContextRepository).saveContext(any(SecurityContext.class), eq(request), eq(response));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.security.cas.SamlServiceProperties;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests {@link ServiceProperties}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class ServicePropertiesTests {
|
||||
|
||||
@Test
|
||||
public void detectsMissingService() throws Exception {
|
||||
ServiceProperties sp = new ServiceProperties();
|
||||
assertThatIllegalArgumentException().isThrownBy(sp::afterPropertiesSet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullServiceWhenAuthenticateAllTokens() throws Exception {
|
||||
ServiceProperties sp = new ServiceProperties();
|
||||
sp.setAuthenticateAllArtifacts(true);
|
||||
assertThatIllegalArgumentException().isThrownBy(sp::afterPropertiesSet);
|
||||
sp.setAuthenticateAllArtifacts(false);
|
||||
assertThatIllegalArgumentException().isThrownBy(sp::afterPropertiesSet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGettersSetters() throws Exception {
|
||||
ServiceProperties[] sps = { new ServiceProperties(), new SamlServiceProperties() };
|
||||
for (ServiceProperties sp : sps) {
|
||||
sp.setSendRenew(false);
|
||||
assertThat(sp.isSendRenew()).isFalse();
|
||||
sp.setSendRenew(true);
|
||||
assertThat(sp.isSendRenew()).isTrue();
|
||||
sp.setArtifactParameter("notticket");
|
||||
assertThat(sp.getArtifactParameter()).isEqualTo("notticket");
|
||||
sp.setServiceParameter("notservice");
|
||||
assertThat(sp.getServiceParameter()).isEqualTo("notservice");
|
||||
sp.setService("https://mycompany.com/service");
|
||||
assertThat(sp.getService()).isEqualTo("https://mycompany.com/service");
|
||||
sp.afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.cas.web.authentication;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class DefaultServiceAuthenticationDetailsTests {
|
||||
|
||||
private DefaultServiceAuthenticationDetails details;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private Pattern artifactPattern;
|
||||
|
||||
private String casServiceUrl;
|
||||
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
this.casServiceUrl = "https://localhost:8443/j_spring_security_cas";
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.request.setScheme("https");
|
||||
this.request.setServerName("localhost");
|
||||
this.request.setServerPort(8443);
|
||||
this.request.setRequestURI("/cas-sample/secure/");
|
||||
this.artifactPattern = DefaultServiceAuthenticationDetails
|
||||
.createArtifactPattern(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanup() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlNullQuery() throws Exception {
|
||||
this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
|
||||
assertThat(this.details.getServiceUrl()).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlTicketOnlyParam() throws Exception {
|
||||
this.request.setQueryString("ticket=123");
|
||||
this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
|
||||
String serviceUrl = this.details.getServiceUrl();
|
||||
this.request.setQueryString(null);
|
||||
assertThat(serviceUrl).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlTicketFirstMultiParam() throws Exception {
|
||||
this.request.setQueryString("ticket=123&other=value");
|
||||
this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
|
||||
String serviceUrl = this.details.getServiceUrl();
|
||||
this.request.setQueryString("other=value");
|
||||
assertThat(serviceUrl).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlTicketLastMultiParam() throws Exception {
|
||||
this.request.setQueryString("other=value&ticket=123");
|
||||
this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
|
||||
String serviceUrl = this.details.getServiceUrl();
|
||||
this.request.setQueryString("other=value");
|
||||
assertThat(serviceUrl).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlTicketMiddleMultiParam() throws Exception {
|
||||
this.request.setQueryString("other=value&ticket=123&last=this");
|
||||
this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
|
||||
String serviceUrl = this.details.getServiceUrl();
|
||||
this.request.setQueryString("other=value&last=this");
|
||||
assertThat(serviceUrl).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlDoesNotUseHostHeader() throws Exception {
|
||||
this.casServiceUrl = "https://example.com/j_spring_security_cas";
|
||||
this.request.setServerName("evil.com");
|
||||
this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
|
||||
assertThat(this.details.getServiceUrl()).isEqualTo("https://example.com/cas-sample/secure/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlDoesNotUseHostHeaderExplicit() {
|
||||
this.casServiceUrl = "https://example.com/j_spring_security_cas";
|
||||
this.request.setServerName("evil.com");
|
||||
ServiceAuthenticationDetails details = loadServiceAuthenticationDetails(
|
||||
"defaultserviceauthenticationdetails-explicit.xml");
|
||||
assertThat(details.getServiceUrl()).isEqualTo("https://example.com/cas-sample/secure/");
|
||||
}
|
||||
|
||||
private ServiceAuthenticationDetails loadServiceAuthenticationDetails(String resourceName) {
|
||||
this.context = new GenericXmlApplicationContext(getClass(), resourceName);
|
||||
ServiceAuthenticationDetailsSource source = this.context.getBean(ServiceAuthenticationDetailsSource.class);
|
||||
return source.buildDetails(this.request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.security" level="${sec.log.level:-WARN}"/>
|
||||
|
||||
|
||||
<root level="${root.level:-WARN}">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
|
||||
|
||||
<bean id="serviceProperties"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
<bean id="serviceProperties2"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example2.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
|
||||
<constructor-arg ref="serviceProperties"/>
|
||||
</bean>
|
||||
</beans>
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
|
||||
|
||||
<bean id="serviceProperties"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
|
||||
</beans>
|
||||
@@ -1,13 +1,11 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.springframework.gradle.xsd.CreateVersionlessXsdTask
|
||||
import trang.RncToXsd
|
||||
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'trang'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
repositories {
|
||||
maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
management platform(project(":spring-security-dependencies"))
|
||||
// NB: Don't add other compile time dependencies to the config module as this breaks tooling
|
||||
@@ -41,7 +39,6 @@ dependencies {
|
||||
provided 'jakarta.servlet:jakarta.servlet-api'
|
||||
|
||||
testImplementation project(':spring-security-aspects')
|
||||
testImplementation project(':spring-security-cas')
|
||||
testImplementation project(':spring-security-test')
|
||||
testImplementation project(path : ':spring-security-core', configuration : 'tests')
|
||||
testImplementation project(path : ':spring-security-ldap', configuration : 'tests')
|
||||
@@ -119,13 +116,31 @@ dependencies {
|
||||
testRuntimeOnly 'org.hsqldb:hsqldb'
|
||||
}
|
||||
|
||||
def versionlessXsd = project.tasks.create("versionlessXsd", CreateVersionlessXsdTask) {
|
||||
inputFiles.from(project.sourceSets.main.resources)
|
||||
versionlessXsdFile = project.layout.buildDirectory.file("versionlessXsd/spring-security.xsd")
|
||||
}
|
||||
|
||||
rncToXsd {
|
||||
processResources {
|
||||
from(versionlessXsd) {
|
||||
into 'org/springframework/security/config/'
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named('rncToXsd', RncToXsd).configure {
|
||||
rncDir = file('src/main/resources/org/springframework/security/config/')
|
||||
xsdDir = rncDir
|
||||
xslFile = new File(rncDir, 'spring-security.xsl')
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
resources {
|
||||
srcDir(tasks.named('rncToXsd'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(KotlinCompile).configureEach {
|
||||
kotlinOptions {
|
||||
languageVersion = "1.7"
|
||||
@@ -134,5 +149,3 @@ tasks.withType(KotlinCompile).configureEach {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
|
||||
build.dependsOn rncToXsd
|
||||
|
||||
+2
-2
@@ -95,7 +95,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
if (!namespaceMatchesVersion(element)) {
|
||||
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or "
|
||||
+ "spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
|
||||
+ "with Spring Security 6.1. Please update your schema declarations to the 6.1 schema.", element);
|
||||
+ "with Spring Security 6.0. Please update your schema declarations to the 6.0 schema.", element);
|
||||
}
|
||||
String name = pc.getDelegate().getLocalName(element);
|
||||
BeanDefinitionParser parser = this.parsers.get(name);
|
||||
@@ -218,7 +218,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
private boolean matchesVersionInternal(Element element) {
|
||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||
return schemaLocation.matches("(?m).*spring-security-6\\.1.*.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-6\\.0.*.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -53,9 +53,7 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
|
||||
* Return the {@link SecurityBuilder} when done using the {@link SecurityConfigurer}.
|
||||
* This is useful for method chaining.
|
||||
* @return the {@link SecurityBuilder} for further customizations
|
||||
* @deprecated For removal in 7.0. Use the lambda based configuration instead.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public B and() {
|
||||
return getBuilder();
|
||||
}
|
||||
|
||||
+4
@@ -36,6 +36,10 @@ class MethodSecurityAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
}
|
||||
|
||||
private void registerAsAdvisor(String prefix, BeanDefinitionRegistry registry) {
|
||||
String advisorName = prefix + "Advisor";
|
||||
if (registry.containsBeanDefinition(advisorName)) {
|
||||
return;
|
||||
}
|
||||
String interceptorName = prefix + "MethodInterceptor";
|
||||
if (!registry.containsBeanDefinition(interceptorName)) {
|
||||
return;
|
||||
|
||||
+51
-4
@@ -16,8 +16,11 @@
|
||||
|
||||
package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -25,6 +28,9 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
||||
@@ -36,7 +42,9 @@ import org.springframework.security.authorization.method.PostFilterAuthorization
|
||||
import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager;
|
||||
import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor;
|
||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
/**
|
||||
* Base {@link Configuration} for enabling Spring Security Method Security.
|
||||
@@ -59,7 +67,7 @@ final class PrePostMethodSecurityConfiguration {
|
||||
PreFilterAuthorizationMethodInterceptor preFilter = new PreFilterAuthorizationMethodInterceptor();
|
||||
strategyProvider.ifAvailable(preFilter::setSecurityContextHolderStrategy);
|
||||
preFilter.setExpressionHandler(
|
||||
expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context)));
|
||||
new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context));
|
||||
return preFilter;
|
||||
}
|
||||
|
||||
@@ -73,7 +81,7 @@ final class PrePostMethodSecurityConfiguration {
|
||||
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
|
||||
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
|
||||
manager.setExpressionHandler(
|
||||
expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context)));
|
||||
new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context));
|
||||
AuthorizationManagerBeforeMethodInterceptor preAuthorize = AuthorizationManagerBeforeMethodInterceptor
|
||||
.preAuthorize(manager(manager, registryProvider));
|
||||
strategyProvider.ifAvailable(preAuthorize::setSecurityContextHolderStrategy);
|
||||
@@ -91,7 +99,7 @@ final class PrePostMethodSecurityConfiguration {
|
||||
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
manager.setExpressionHandler(
|
||||
expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context)));
|
||||
new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context));
|
||||
AuthorizationManagerAfterMethodInterceptor postAuthorize = AuthorizationManagerAfterMethodInterceptor
|
||||
.postAuthorize(manager(manager, registryProvider));
|
||||
strategyProvider.ifAvailable(postAuthorize::setSecurityContextHolderStrategy);
|
||||
@@ -108,7 +116,7 @@ final class PrePostMethodSecurityConfiguration {
|
||||
PostFilterAuthorizationMethodInterceptor postFilter = new PostFilterAuthorizationMethodInterceptor();
|
||||
strategyProvider.ifAvailable(postFilter::setSecurityContextHolderStrategy);
|
||||
postFilter.setExpressionHandler(
|
||||
expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context)));
|
||||
new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context));
|
||||
return postFilter;
|
||||
}
|
||||
|
||||
@@ -125,4 +133,43 @@ final class PrePostMethodSecurityConfiguration {
|
||||
return new DeferringObservationAuthorizationManager<>(registryProvider, delegate);
|
||||
}
|
||||
|
||||
private static final class DeferringMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler {
|
||||
|
||||
private final Supplier<MethodSecurityExpressionHandler> expressionHandler;
|
||||
|
||||
private DeferringMethodSecurityExpressionHandler(
|
||||
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
|
||||
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider, ApplicationContext applicationContext) {
|
||||
this.expressionHandler = SingletonSupplier.of(() -> expressionHandlerProvider
|
||||
.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, applicationContext)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionParser getExpressionParser() {
|
||||
return this.expressionHandler.get().getExpressionParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvaluationContext createEvaluationContext(Authentication authentication, MethodInvocation invocation) {
|
||||
return this.expressionHandler.get().createEvaluationContext(authentication, invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvaluationContext createEvaluationContext(Supplier<Authentication> authentication,
|
||||
MethodInvocation invocation) {
|
||||
return this.expressionHandler.get().createEvaluationContext(authentication, invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) {
|
||||
return this.expressionHandler.get().filter(filterTarget, filterExpression, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReturnObject(Object returnObject, EvaluationContext ctx) {
|
||||
this.expressionHandler.get().setReturnObject(returnObject, ctx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+32
-4
@@ -18,6 +18,8 @@ package org.springframework.security.config.annotation.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -194,18 +196,31 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
if (servletContext == null) {
|
||||
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
||||
}
|
||||
Map<String, ? extends ServletRegistration> registrations = servletContext.getServletRegistrations();
|
||||
if (registrations == null) {
|
||||
Map<String, ? extends ServletRegistration> registrations = mappableServletRegistrations(servletContext);
|
||||
if (registrations.isEmpty()) {
|
||||
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
||||
}
|
||||
if (!hasDispatcherServlet(registrations)) {
|
||||
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
||||
}
|
||||
Assert.isTrue(registrations.size() == 1,
|
||||
"This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).");
|
||||
if (registrations.size() > 1) {
|
||||
String errorMessage = computeErrorMessage(registrations.values());
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
return requestMatchers(createMvcMatchers(method, patterns).toArray(new RequestMatcher[0]));
|
||||
}
|
||||
|
||||
private Map<String, ? extends ServletRegistration> mappableServletRegistrations(ServletContext servletContext) {
|
||||
Map<String, ServletRegistration> mappable = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, ? extends ServletRegistration> entry : servletContext.getServletRegistrations()
|
||||
.entrySet()) {
|
||||
if (!entry.getValue().getMappings().isEmpty()) {
|
||||
mappable.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return mappable;
|
||||
}
|
||||
|
||||
private boolean hasDispatcherServlet(Map<String, ? extends ServletRegistration> registrations) {
|
||||
if (registrations == null) {
|
||||
return false;
|
||||
@@ -226,6 +241,19 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
return false;
|
||||
}
|
||||
|
||||
private String computeErrorMessage(Collection<? extends ServletRegistration> registrations) {
|
||||
String template = "This method cannot decide whether these patterns are Spring MVC patterns or not. "
|
||||
+ "If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); "
|
||||
+ "otherwise, please use requestMatchers(AntPathRequestMatcher).\n\n"
|
||||
+ "This is because there is more than one mappable servlet in your servlet context: %s.\n\n"
|
||||
+ "For each MvcRequestMatcher, call MvcRequestMatcher#setServletPath to indicate the servlet path.";
|
||||
Map<String, Collection<String>> mappings = new LinkedHashMap<>();
|
||||
for (ServletRegistration registration : registrations) {
|
||||
mappings.put(registration.getClassName(), registration.getMappings());
|
||||
}
|
||||
return String.format(template, mappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
|
||||
|
||||
+2
-258
@@ -73,7 +73,6 @@ import org.springframework.security.config.annotation.web.configurers.oauth2.cli
|
||||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.saml2.Saml2LoginConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.saml2.Saml2LogoutConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.saml2.Saml2MetadataConfigurer;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@@ -285,13 +284,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link HeadersConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #headers(Customizer)} or
|
||||
* {@code headers(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see HeadersConfigurer
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<HttpSecurity> headers() throws Exception {
|
||||
return getOrApply(new HeadersConfigurer<>());
|
||||
}
|
||||
@@ -404,12 +398,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* on the classpath a {@link HandlerMappingIntrospector} is used.
|
||||
* @return the {@link CorsConfigurer} for customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #cors(Customizer)} or
|
||||
* {@code cors(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CorsConfigurer<HttpSecurity> cors() throws Exception {
|
||||
return getOrApply(new CorsConfigurer<>());
|
||||
}
|
||||
@@ -496,13 +485,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* could return true.
|
||||
* @return the {@link SessionManagementConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #sessionManagement(Customizer)} or
|
||||
* {@code sessionManagement(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public SessionManagementConfigurer<HttpSecurity> sessionManagement() throws Exception {
|
||||
return getOrApply(new SessionManagementConfigurer<>());
|
||||
}
|
||||
@@ -624,14 +607,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link PortMapperConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #portMapper(Customizer)} or
|
||||
* {@code portMapper(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see #requiresChannel()
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public PortMapperConfigurer<HttpSecurity> portMapper() throws Exception {
|
||||
return getOrApply(new PortMapperConfigurer<>());
|
||||
}
|
||||
@@ -761,12 +738,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* Servlet Container's documentation.
|
||||
* @return the {@link JeeConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #jee(Customizer)} or
|
||||
* {@code jee(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public JeeConfigurer<HttpSecurity> jee() throws Exception {
|
||||
return getOrApply(new JeeConfigurer<>());
|
||||
}
|
||||
@@ -877,12 +849,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link X509Configurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #x509(Customizer)} or
|
||||
* {@code x509(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public X509Configurer<HttpSecurity> x509() throws Exception {
|
||||
return getOrApply(new X509Configurer<>());
|
||||
}
|
||||
@@ -960,13 +927,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link RememberMeConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #rememberMe(Customizer)} or
|
||||
* {@code rememberMe(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public RememberMeConfigurer<HttpSecurity> rememberMe() throws Exception {
|
||||
return getOrApply(new RememberMeConfigurer<>());
|
||||
}
|
||||
@@ -1110,7 +1071,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizeHttpRequests()} instead
|
||||
* @deprecated Use {@link #authorizeHttpRequests()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests()
|
||||
@@ -1225,7 +1186,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* for the {@link ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry}
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizeHttpRequests} instead
|
||||
* @deprecated Use {@link #authorizeHttpRequests} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public HttpSecurity authorizeRequests(
|
||||
@@ -1340,10 +1301,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
* @throws Exception
|
||||
* @since 5.6
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizeHttpRequests(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry authorizeHttpRequests()
|
||||
throws Exception {
|
||||
ApplicationContext context = getContext();
|
||||
@@ -1475,13 +1433,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* when using {@link EnableWebSecurity}.
|
||||
* @return the {@link RequestCacheConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #requestCache(Customizer)} or
|
||||
* {@code requestCache(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public RequestCacheConfigurer<HttpSecurity> requestCache() throws Exception {
|
||||
return getOrApply(new RequestCacheConfigurer<>());
|
||||
}
|
||||
@@ -1532,13 +1484,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* {@link EnableWebSecurity}.
|
||||
* @return the {@link ExceptionHandlingConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #exceptionHandling(Customizer)} or
|
||||
* {@code exceptionHandling(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {
|
||||
return getOrApply(new ExceptionHandlingConfigurer<>());
|
||||
}
|
||||
@@ -1590,13 +1536,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* automatically applied when using {@link EnableWebSecurity}.
|
||||
* @return the {@link SecurityContextConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #securityContext(Customizer)} or
|
||||
* {@code securityContext(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public SecurityContextConfigurer<HttpSecurity> securityContext() throws Exception {
|
||||
return getOrApply(new SecurityContextConfigurer<>());
|
||||
}
|
||||
@@ -1641,13 +1581,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* {@link EnableWebSecurity}.
|
||||
* @return the {@link ServletApiConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #servletApi(Customizer)} or
|
||||
* {@code servletApi(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServletApiConfigurer<HttpSecurity> servletApi() throws Exception {
|
||||
return getOrApply(new ServletApiConfigurer<>());
|
||||
}
|
||||
@@ -1703,12 +1637,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link CsrfConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #csrf(Customizer)} or
|
||||
* {@code csrf(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
|
||||
ApplicationContext context = getContext();
|
||||
return getOrApply(new CsrfConfigurer<>(context));
|
||||
@@ -1783,12 +1712,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link LogoutConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #logout(Customizer)} or
|
||||
* {@code logout(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public LogoutConfigurer<HttpSecurity> logout() throws Exception {
|
||||
return getOrApply(new LogoutConfigurer<>());
|
||||
}
|
||||
@@ -1927,13 +1851,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link AnonymousConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #anonymous(Customizer)} or
|
||||
* {@code anonymous(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AnonymousConfigurer<HttpSecurity> anonymous() throws Exception {
|
||||
return getOrApply(new AnonymousConfigurer<>());
|
||||
}
|
||||
@@ -2096,14 +2014,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link FormLoginConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #formLogin(Customizer)} or
|
||||
* {@code formLogin(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see FormLoginConfigurer#loginPage(String)
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
|
||||
return getOrApply(new FormLoginConfigurer<>());
|
||||
}
|
||||
@@ -2278,13 +2190,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* @return the {@link Saml2LoginConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @since 5.2
|
||||
* @deprecated For removal in 7.0. Use {@link #saml2Login(Customizer)} or
|
||||
* {@code saml2Login(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public Saml2LoginConfigurer<HttpSecurity> saml2Login() throws Exception {
|
||||
return getOrApply(new Saml2LoginConfigurer<>());
|
||||
}
|
||||
@@ -2514,119 +2420,11 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* @return the {@link Saml2LoginConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @since 5.6
|
||||
* @deprecated For removal in 7.0. Use {@link #saml2Logout(Customizer)} or
|
||||
* {@code saml2Logout(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public Saml2LogoutConfigurer<HttpSecurity> saml2Logout() throws Exception {
|
||||
return getOrApply(new Saml2LogoutConfigurer<>(getContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a SAML 2.0 metadata endpoint that presents relying party configurations
|
||||
* in an {@code <md:EntityDescriptor>} payload.
|
||||
*
|
||||
* <p>
|
||||
* By default, the endpoints are {@code /saml2/metadata} and
|
||||
* {@code /saml2/metadata/{registrationId}} though note that also
|
||||
* {@code /saml2/service-provider-metadata/{registrationId}} is recognized for
|
||||
* backward compatibility purposes.
|
||||
*
|
||||
* <p>
|
||||
* <h2>Example Configuration</h2>
|
||||
*
|
||||
* The following example shows the minimal configuration required, using a
|
||||
* hypothetical asserting party.
|
||||
*
|
||||
* <pre>
|
||||
* @EnableWebSecurity
|
||||
* @Configuration
|
||||
* public class Saml2LogoutSecurityConfig {
|
||||
* @Bean
|
||||
* public SecurityFilterChain web(HttpSecurity http) throws Exception {
|
||||
* http
|
||||
* .authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
* .saml2Metadata(Customizer.withDefaults());
|
||||
* return http.build();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
|
||||
* RelyingPartyRegistration registration = RelyingPartyRegistrations
|
||||
* .withMetadataLocation("https://ap.example.org/metadata")
|
||||
* .registrationId("simple")
|
||||
* .build();
|
||||
* return new InMemoryRelyingPartyRegistrationRepository(registration);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* @param saml2MetadataConfigurer the {@link Customizer} to provide more options for
|
||||
* the {@link Saml2MetadataConfigurer}
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
* @throws Exception
|
||||
* @since 6.1
|
||||
*/
|
||||
public HttpSecurity saml2Metadata(Customizer<Saml2MetadataConfigurer<HttpSecurity>> saml2MetadataConfigurer)
|
||||
throws Exception {
|
||||
saml2MetadataConfigurer.customize(getOrApply(new Saml2MetadataConfigurer<>(getContext())));
|
||||
return HttpSecurity.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a SAML 2.0 metadata endpoint that presents relying party configurations
|
||||
* in an {@code <md:EntityDescriptor>} payload.
|
||||
*
|
||||
* <p>
|
||||
* By default, the endpoints are {@code /saml2/metadata} and
|
||||
* {@code /saml2/metadata/{registrationId}} though note that also
|
||||
* {@code /saml2/service-provider-metadata/{registrationId}} is recognized for
|
||||
* backward compatibility purposes.
|
||||
*
|
||||
* <p>
|
||||
* <h2>Example Configuration</h2>
|
||||
*
|
||||
* The following example shows the minimal configuration required, using a
|
||||
* hypothetical asserting party.
|
||||
*
|
||||
* <pre>
|
||||
* @EnableWebSecurity
|
||||
* @Configuration
|
||||
* public class Saml2LogoutSecurityConfig {
|
||||
* @Bean
|
||||
* public SecurityFilterChain web(HttpSecurity http) throws Exception {
|
||||
* http
|
||||
* .authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
* .saml2Metadata(Customizer.withDefaults());
|
||||
* return http.build();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
|
||||
* RelyingPartyRegistration registration = RelyingPartyRegistrations
|
||||
* .withMetadataLocation("https://ap.example.org/metadata")
|
||||
* .registrationId("simple")
|
||||
* .build();
|
||||
* return new InMemoryRelyingPartyRegistrationRepository(registration);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link Saml2MetadataConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @since 6.1
|
||||
* @deprecated For removal in 7.0. Use {@link #saml2Metadata(Customizer)} or
|
||||
* {@code saml2Metadata(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public Saml2MetadataConfigurer<HttpSecurity> saml2Metadata() throws Exception {
|
||||
return getOrApply(new Saml2MetadataConfigurer<>(getContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0
|
||||
* Provider. <br>
|
||||
@@ -2713,11 +2511,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* @return the {@link OAuth2LoginConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @since 5.0
|
||||
* @deprecated For removal in 7.0. Use {@link #oauth2Login(Customizer)} or
|
||||
* {@code oauth2Login(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see <a target="_blank" href=
|
||||
* "https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code
|
||||
* Grant</a>
|
||||
@@ -2727,7 +2520,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* @see org.springframework.security.oauth2.client.registration.ClientRegistration
|
||||
* @see org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginConfigurer<HttpSecurity> oauth2Login() throws Exception {
|
||||
return getOrApply(new OAuth2LoginConfigurer<>());
|
||||
}
|
||||
@@ -2840,16 +2632,10 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* @return the {@link OAuth2ClientConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @since 5.1
|
||||
* @deprecated For removal in 7.0. Use {@link #oauth2Client(Customizer)} or
|
||||
* {@code oauth2Client(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see <a target="_blank" href=
|
||||
* "https://tools.ietf.org/html/rfc6749#section-1.1">OAuth 2.0 Authorization
|
||||
* Framework</a>
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ClientConfigurer<HttpSecurity> oauth2Client() throws Exception {
|
||||
OAuth2ClientConfigurer<HttpSecurity> configurer = getOrApply(new OAuth2ClientConfigurer<>());
|
||||
this.postProcess(configurer);
|
||||
@@ -2900,13 +2686,10 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* @return the {@link OAuth2ResourceServerConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @since 5.1
|
||||
* @deprecated For removal in 7.0. Use {@link #oauth2ResourceServer(Customizer)}
|
||||
* instead
|
||||
* @see <a target="_blank" href=
|
||||
* "https://tools.ietf.org/html/rfc6749#section-1.1">OAuth 2.0 Authorization
|
||||
* Framework</a>
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ResourceServerConfigurer<HttpSecurity> oauth2ResourceServer() throws Exception {
|
||||
OAuth2ResourceServerConfigurer<HttpSecurity> configurer = getOrApply(
|
||||
new OAuth2ResourceServerConfigurer<>(getContext()));
|
||||
@@ -3004,13 +2787,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link ChannelSecurityConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #requiresChannel(Customizer)} or
|
||||
* {@code requiresChannel(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ChannelSecurityConfigurer<HttpSecurity>.ChannelRequestMatcherRegistry requiresChannel() throws Exception {
|
||||
ApplicationContext context = getContext();
|
||||
return getOrApply(new ChannelSecurityConfigurer<>(context)).getRegistry();
|
||||
@@ -3105,13 +2882,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </pre>
|
||||
* @return the {@link HttpBasicConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @deprecated For removal in 7.0. Use {@link #httpBasic(Customizer)} or
|
||||
* {@code httpBasic(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HttpBasicConfigurer<HttpSecurity> httpBasic() throws Exception {
|
||||
return getOrApply(new HttpBasicConfigurer<>());
|
||||
}
|
||||
@@ -3440,13 +3211,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link RequestMatcherConfigurer} for further customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #securityMatchers(Customizer)} or
|
||||
* {@code securityMatchers(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public RequestMatcherConfigurer securityMatchers() {
|
||||
return this.requestMatcherConfigurer;
|
||||
}
|
||||
@@ -3704,28 +3469,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
/**
|
||||
* Return the {@link HttpSecurity} for further customizations
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
* @deprecated Use the lambda based configuration instead. For example: <pre>
|
||||
* @Configuration
|
||||
* @EnableWebSecurity
|
||||
* public class SecurityConfig {
|
||||
*
|
||||
* @Bean
|
||||
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
* http
|
||||
* .securityMatchers((matchers) -> matchers
|
||||
* .requestMatchers("/api/**")
|
||||
* )
|
||||
* .authorizeHttpRequests((authorize) -> authorize
|
||||
* .anyRequest().hasRole("USER")
|
||||
* )
|
||||
* .httpBasic(Customizer.withDefaults());
|
||||
* return http.build();
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HttpSecurity and() {
|
||||
return HttpSecurity.this;
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
*
|
||||
* @Bean
|
||||
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
* http.authorizeHttpRequests().requestMatchers("/public/**").permitAll().anyRequest()
|
||||
* http.authorizeRequests().requestMatchers("/public/**").permitAll().anyRequest()
|
||||
* .hasRole("USER").and()
|
||||
* // Possibly more configuration ...
|
||||
* .formLogin() // enable form based log in
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -51,8 +51,8 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
* Base class for configuring {@link AbstractAuthenticationFilterConfigurer}. This is
|
||||
* intended for internal use only.
|
||||
*
|
||||
* @param <T> refers to "this" for returning the current configurer
|
||||
* @param <F> refers to the {@link AbstractAuthenticationProcessingFilter} that is being
|
||||
* @param T refers to "this" for returning the current configurer
|
||||
* @param F refers to the {@link AbstractAuthenticationProcessingFilter} that is being
|
||||
* built
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
@@ -122,7 +122,7 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
* true. This is a shortcut for calling
|
||||
* {@link #successHandler(AuthenticationSuccessHandler)}.
|
||||
* @param defaultSuccessUrl the default success url
|
||||
* @param alwaysUse true if the {@code defaultSuccessUrl} should be used after
|
||||
* @param alwaysUse true if the {@code defaultSuccesUrl} should be used after
|
||||
* authentication despite if a protected page had been previously visited
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
@@ -380,6 +380,7 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
|
||||
/**
|
||||
* Updates the default values for authentication.
|
||||
* @throws Exception
|
||||
*/
|
||||
protected final void updateAuthenticationDefaults() {
|
||||
if (this.loginProcessingUrl == null) {
|
||||
|
||||
+5
-39
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,14 +17,11 @@
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
@@ -41,7 +38,6 @@ import org.springframework.security.web.access.intercept.RequestMatcherDelegatin
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
/**
|
||||
* Adds a URL based authorization using {@link AuthorizationManager}.
|
||||
@@ -60,8 +56,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
|
||||
private final AuthorizationEventPublisher publisher;
|
||||
|
||||
private final Supplier<RoleHierarchy> roleHierarchy;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param context the {@link ApplicationContext} to use
|
||||
@@ -74,8 +68,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
else {
|
||||
this.publisher = new SpringAuthorizationEventPublisher(context);
|
||||
}
|
||||
this.roleHierarchy = SingletonSupplier.of(() -> (context.getBeanNamesForType(RoleHierarchy.class).length > 0)
|
||||
? context.getBean(RoleHierarchy.class) : new NullRoleHierarchy());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,25 +186,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
|
||||
* customizations
|
||||
* @since 5.7
|
||||
* @deprecated Permit access to the {@link jakarta.servlet.DispatcherType}
|
||||
* instead. <pre>
|
||||
* @Configuration
|
||||
* @EnableWebSecurity
|
||||
* public class SecurityConfig {
|
||||
*
|
||||
* @Bean
|
||||
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
* http
|
||||
* .authorizeHttpRequests((authorize) -> authorize
|
||||
* .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
|
||||
* // ...
|
||||
* );
|
||||
* return http.build();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AuthorizationManagerRequestMatcherRegistry shouldFilterAllDispatcherTypes(boolean shouldFilter) {
|
||||
this.shouldFilterAllDispatcherTypes = shouldFilter;
|
||||
return this;
|
||||
@@ -222,9 +196,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
* Return the {@link HttpSecurityBuilder} when done using the
|
||||
* {@link AuthorizeHttpRequestsConfigurer}. This is useful for method chaining.
|
||||
* @return the {@link HttpSecurityBuilder} for further customizations
|
||||
* @deprecated For removal in 7.0. Use the lambda based configuration instead.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public H and() {
|
||||
return AuthorizeHttpRequestsConfigurer.this.and();
|
||||
}
|
||||
@@ -279,7 +251,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
* customizations
|
||||
*/
|
||||
public AuthorizationManagerRequestMatcherRegistry hasRole(String role) {
|
||||
return access(withRoleHierarchy(AuthorityAuthorizationManager.hasRole(role)));
|
||||
return access(AuthorityAuthorizationManager.hasRole(role));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,7 +263,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
* customizations
|
||||
*/
|
||||
public AuthorizationManagerRequestMatcherRegistry hasAnyRole(String... roles) {
|
||||
return access(withRoleHierarchy(AuthorityAuthorizationManager.hasAnyRole(roles)));
|
||||
return access(AuthorityAuthorizationManager.hasAnyRole(roles));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +273,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
* customizations
|
||||
*/
|
||||
public AuthorizationManagerRequestMatcherRegistry hasAuthority(String authority) {
|
||||
return access(withRoleHierarchy(AuthorityAuthorizationManager.hasAuthority(authority)));
|
||||
return access(AuthorityAuthorizationManager.hasAuthority(authority));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,13 +284,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
* customizations
|
||||
*/
|
||||
public AuthorizationManagerRequestMatcherRegistry hasAnyAuthority(String... authorities) {
|
||||
return access(withRoleHierarchy(AuthorityAuthorizationManager.hasAnyAuthority(authorities)));
|
||||
}
|
||||
|
||||
private AuthorityAuthorizationManager<RequestAuthorizationContext> withRoleHierarchy(
|
||||
AuthorityAuthorizationManager<RequestAuthorizationContext> manager) {
|
||||
manager.setRoleHierarchy(AuthorizeHttpRequestsConfigurer.this.roleHierarchy.get());
|
||||
return manager;
|
||||
return access(AuthorityAuthorizationManager.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,7 +24,6 @@ import java.util.List;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
@@ -195,10 +194,7 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* Return the {@link SecurityBuilder} when done using the
|
||||
* {@link SecurityConfigurer}. This is useful for method chaining.
|
||||
* @return the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link HttpSecurity#requiresChannel(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public H and() {
|
||||
return ChannelSecurityConfigurer.this.and();
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+3
-112
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,7 +24,6 @@ import java.util.Map;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
@@ -136,13 +135,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* X-Content-Type-Options: nosniff
|
||||
* </pre>
|
||||
* @return the {@link ContentTypeOptionsConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)} or
|
||||
* {@code contentTypeOptions(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ContentTypeOptionsConfig contentTypeOptions() {
|
||||
return this.contentTypeOptions.enable();
|
||||
}
|
||||
@@ -173,13 +166,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* >X-XSS-Protection header</a>
|
||||
* </p>
|
||||
* @return the {@link XXssConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or
|
||||
* {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public XXssConfig xssProtection() {
|
||||
return this.xssProtection.enable();
|
||||
}
|
||||
@@ -210,13 +197,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* <li>Expires: 0</li>
|
||||
* </ul>
|
||||
* @return the {@link CacheControlConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #cacheControl(Customizer)} or
|
||||
* {@code cacheControl(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CacheControlConfig cacheControl() {
|
||||
return this.cacheControl.enable();
|
||||
}
|
||||
@@ -243,10 +224,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
|
||||
* (HSTS)</a>.
|
||||
* @return the {@link HstsConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #httpStrictTransportSecurity(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HstsConfig httpStrictTransportSecurity() {
|
||||
return this.hsts.enable();
|
||||
}
|
||||
@@ -267,13 +245,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* Allows customizing the {@link XFrameOptionsHeaderWriter}.
|
||||
* @return the {@link FrameOptionsConfig} for additional customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or
|
||||
* {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public FrameOptionsConfig frameOptions() {
|
||||
return this.frameOptions.enable();
|
||||
}
|
||||
@@ -343,11 +315,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* @return the {@link ContentSecurityPolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if policyDirectives is null or empty
|
||||
* @since 4.1
|
||||
* @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)}
|
||||
* instead
|
||||
* @see ContentSecurityPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ContentSecurityPolicyConfig contentSecurityPolicy(String policyDirectives) {
|
||||
this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(policyDirectives);
|
||||
return this.contentSecurityPolicy;
|
||||
@@ -477,14 +446,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* </pre>
|
||||
* @return the {@link ReferrerPolicyConfig} for additional configuration
|
||||
* @since 4.2
|
||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or
|
||||
* {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see ReferrerPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ReferrerPolicyConfig referrerPolicy() {
|
||||
this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter();
|
||||
return this.referrerPolicy;
|
||||
@@ -506,14 +469,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* @return the {@link ReferrerPolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if policy is null or empty
|
||||
* @since 4.2
|
||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or
|
||||
* {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see ReferrerPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) {
|
||||
this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(policy);
|
||||
return this.referrerPolicy;
|
||||
@@ -555,12 +512,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* @return the {@link FeaturePolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if policyDirectives is {@code null} or empty
|
||||
* @since 5.1
|
||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)} or
|
||||
* {@code permissionsPolicy(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see ObjectPostProcessorConfiguration FeaturePolicyHeaderWriter
|
||||
* @deprecated Use {@link #permissionsPolicy(Customizer)} instead.
|
||||
* @seeObjectPostProcessorConfiguration FeaturePolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated
|
||||
public FeaturePolicyConfig featurePolicy(String policyDirectives) {
|
||||
@@ -584,14 +537,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* </ul>
|
||||
* @return the {@link PermissionsPolicyConfig} for additional configuration
|
||||
* @since 5.5
|
||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)} or
|
||||
* {@code permissionsPolicy(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
* @see PermissionsPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public PermissionsPolicyConfig permissionsPolicy() {
|
||||
this.permissionsPolicy.writer = new PermissionsPolicyHeaderWriter();
|
||||
return this.permissionsPolicy;
|
||||
@@ -628,11 +575,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* </p>
|
||||
* @return the {@link CrossOriginOpenerPolicyConfig} for additional confniguration
|
||||
* @since 5.7
|
||||
* @deprecated For removal in 7.0. Use {@link #crossOriginOpenerPolicy(Customizer)}
|
||||
* instead
|
||||
* @see CrossOriginOpenerPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy() {
|
||||
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
|
||||
return this.crossOriginOpenerPolicy;
|
||||
@@ -672,11 +616,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* </p>
|
||||
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional customizations
|
||||
* @since 5.7
|
||||
* @deprecated For removal in 7.0. Use {@link #crossOriginEmbedderPolicy(Customizer)}
|
||||
* instead
|
||||
* @see CrossOriginEmbedderPolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy() {
|
||||
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
|
||||
return this.crossOriginEmbedderPolicy;
|
||||
@@ -716,11 +657,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @deprecated For removal in 7.0. Use {@link #crossOriginResourcePolicy(Customizer)}
|
||||
* instead
|
||||
* @see CrossOriginResourcePolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CrossOriginResourcePolicyConfig crossOriginResourcePolicy() {
|
||||
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
|
||||
return this.crossOriginResourcePolicy;
|
||||
@@ -770,10 +708,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* Allows customizing the {@link HeadersConfigurer}
|
||||
* @return the {@link HeadersConfigurer} for additional customization
|
||||
* @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -846,13 +781,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* Allows completing configuration of X-XSS-Protection and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or
|
||||
* {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -891,13 +820,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* Allows completing configuration of Cache Control and continuing configuration
|
||||
* of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #cacheControl(Customizer)} or
|
||||
* {@code cacheControl(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -1003,10 +926,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* Allows completing configuration of Strict Transport Security and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #httpStrictTransportSecurity(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -1067,13 +987,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* Allows continuing customizing the headers configuration.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or
|
||||
* {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -1296,10 +1210,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* Allows completing configuration of Content Security Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -1324,14 +1235,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or
|
||||
* {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -1378,10 +1281,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* Allows completing configuration of Permissions Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -1411,10 +1311,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* Allows completing configuration of Cross Origin Opener Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginOpenerPolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -1445,10 +1342,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* Allows completing configuration of Cross-Origin-Embedder-Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginEmbedderPolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
@@ -1479,10 +1373,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* Allows completing configuration of Cross-Origin-Resource-Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginResourcePolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
+1
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,8 +36,6 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS
|
||||
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||
@@ -77,7 +75,6 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Evgeniy Cheban
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
@@ -94,8 +91,6 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
private BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
|
||||
|
||||
private SecurityContextRepository securityContextRepository;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#httpBasic()
|
||||
@@ -147,19 +142,6 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a custom {@link SecurityContextRepository} to use for basic
|
||||
* authentication. The default is {@link RequestAttributeSecurityContextRepository}.
|
||||
* @param securityContextRepository the custom {@link SecurityContextRepository} to
|
||||
* use
|
||||
* @return {@link HttpBasicConfigurer} for additional customization
|
||||
* @since 6.1
|
||||
*/
|
||||
public HttpBasicConfigurer<B> securityContextRepository(SecurityContextRepository securityContextRepository) {
|
||||
this.securityContextRepository = securityContextRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(B http) {
|
||||
registerDefaults(http);
|
||||
@@ -213,9 +195,6 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
if (this.authenticationDetailsSource != null) {
|
||||
basicAuthenticationFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
|
||||
}
|
||||
if (this.securityContextRepository != null) {
|
||||
basicAuthenticationFilter.setSecurityContextRepository(this.securityContextRepository);
|
||||
}
|
||||
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
|
||||
if (rememberMeServices != null) {
|
||||
basicAuthenticationFilter.setRememberMeServices(rememberMeServices);
|
||||
|
||||
+1
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -769,10 +769,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* Used to chain back to the {@link SessionManagementConfigurer}
|
||||
* @return the {@link SessionManagementConfigurer} for further customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #sessionConcurrency(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public SessionManagementConfigurer<H> and() {
|
||||
return SessionManagementConfigurer.this;
|
||||
}
|
||||
|
||||
+1
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -136,10 +136,7 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
* Returns the {@link AuthorizationCodeGrantConfigurer} for configuring the OAuth 2.0
|
||||
* Authorization Code Grant.
|
||||
* @return the {@link AuthorizationCodeGrantConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizationCodeGrant(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AuthorizationCodeGrantConfigurer authorizationCodeGrant() {
|
||||
return this.authorizationCodeGrantConfigurer;
|
||||
}
|
||||
@@ -236,10 +233,7 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
/**
|
||||
* Returns the {@link OAuth2ClientConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2ClientConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizationCodeGrant(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ClientConfigurer<B> and() {
|
||||
return OAuth2ClientConfigurer.this;
|
||||
}
|
||||
|
||||
+1
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -206,10 +206,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
* Returns the {@link AuthorizationEndpointConfig} for configuring the Authorization
|
||||
* Server's Authorization Endpoint.
|
||||
* @return the {@link AuthorizationEndpointConfig}
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizationEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AuthorizationEndpointConfig authorizationEndpoint() {
|
||||
return this.authorizationEndpointConfig;
|
||||
}
|
||||
@@ -230,13 +227,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
* Returns the {@link TokenEndpointConfig} for configuring the Authorization Server's
|
||||
* Token Endpoint.
|
||||
* @return the {@link TokenEndpointConfig}
|
||||
* @deprecated For removal in 7.0. Use {@link #tokenEndpoint(Customizer)} or
|
||||
* {@code tokenEndpoint(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public TokenEndpointConfig tokenEndpoint() {
|
||||
return this.tokenEndpointConfig;
|
||||
}
|
||||
@@ -257,10 +248,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
* Returns the {@link RedirectionEndpointConfig} for configuring the Client's
|
||||
* Redirection Endpoint.
|
||||
* @return the {@link RedirectionEndpointConfig}
|
||||
* @deprecated For removal in 7.0. Use {@link #redirectionEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public RedirectionEndpointConfig redirectionEndpoint() {
|
||||
return this.redirectionEndpointConfig;
|
||||
}
|
||||
@@ -281,13 +269,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
* Returns the {@link UserInfoEndpointConfig} for configuring the Authorization
|
||||
* Server's UserInfo Endpoint.
|
||||
* @return the {@link UserInfoEndpointConfig}
|
||||
* @deprecated For removal in 7.0. Use {@link #userInfoEndpoint(Customizer)} or
|
||||
* {@code userInfoEndpoint(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public UserInfoEndpointConfig userInfoEndpoint() {
|
||||
return this.userInfoEndpointConfig;
|
||||
}
|
||||
@@ -608,10 +590,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
/**
|
||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2LoginConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizationEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginConfigurer<B> and() {
|
||||
return OAuth2LoginConfigurer.this;
|
||||
}
|
||||
@@ -645,13 +624,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
/**
|
||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2LoginConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #tokenEndpoint(Customizer)} or
|
||||
* {@code tokenEndpoint(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginConfigurer<B> and() {
|
||||
return OAuth2LoginConfigurer.this;
|
||||
}
|
||||
@@ -683,10 +656,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
/**
|
||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2LoginConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #redirectionEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginConfigurer<B> and() {
|
||||
return OAuth2LoginConfigurer.this;
|
||||
}
|
||||
@@ -748,10 +718,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
/**
|
||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
||||
* @return the {@link OAuth2LoginConfigurer}
|
||||
* @deprecated For removal in 7.0. Use {@link #userInfoEndpoint(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginConfigurer<B> and() {
|
||||
return OAuth2LoginConfigurer.this;
|
||||
}
|
||||
|
||||
+1
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -198,13 +198,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
|
||||
* {@code jwt(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public JwtConfigurer jwt() {
|
||||
if (this.jwtConfigurer == null) {
|
||||
this.jwtConfigurer = new JwtConfigurer(this.context);
|
||||
@@ -226,14 +219,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #opaqueToken(Customizer)} or
|
||||
* {@code opaqueToken(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OpaqueTokenConfigurer opaqueToken() {
|
||||
if (this.opaqueTokenConfigurer == null) {
|
||||
this.opaqueTokenConfigurer = new OpaqueTokenConfigurer(this.context);
|
||||
@@ -409,13 +394,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
|
||||
* {@code jwt(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ResourceServerConfigurer<H> and() {
|
||||
return OAuth2ResourceServerConfigurer.this;
|
||||
}
|
||||
|
||||
+20
-15
@@ -33,8 +33,9 @@ import org.springframework.security.saml2.provider.service.authentication.Abstra
|
||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.OpenSamlAuthenticationTokenConverter;
|
||||
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
|
||||
import org.springframework.security.saml2.provider.service.web.Saml2WebSsoAuthenticationRequestFilter;
|
||||
@@ -268,6 +269,9 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
}
|
||||
}
|
||||
this.initDefaultLoginFilter(http);
|
||||
if (this.authenticationManager == null) {
|
||||
registerDefaultAuthenticationProvider(http);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,14 +287,16 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
filter.setAuthenticationRequestRepository(getAuthenticationRequestRepository(http));
|
||||
http.addFilter(postProcess(filter));
|
||||
super.configure(http);
|
||||
if (this.authenticationManager == null) {
|
||||
registerDefaultAuthenticationProvider(http);
|
||||
}
|
||||
else {
|
||||
if (this.authenticationManager != null) {
|
||||
this.saml2WebSsoAuthenticationFilter.setAuthenticationManager(this.authenticationManager);
|
||||
}
|
||||
}
|
||||
|
||||
private RelyingPartyRegistrationResolver relyingPartyRegistrationResolver(B http) {
|
||||
RelyingPartyRegistrationRepository registrations = relyingPartyRegistrationRepository(http);
|
||||
return new DefaultRelyingPartyRegistrationResolver(registrations);
|
||||
}
|
||||
|
||||
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository(B http) {
|
||||
if (this.relyingPartyRegistrationRepository == null) {
|
||||
this.relyingPartyRegistrationRepository = getSharedOrBean(http, RelyingPartyRegistrationRepository.class);
|
||||
@@ -333,7 +339,7 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return bean;
|
||||
}
|
||||
OpenSaml4AuthenticationRequestResolver openSaml4AuthenticationRequestResolver = new OpenSaml4AuthenticationRequestResolver(
|
||||
relyingPartyRegistrationRepository(http));
|
||||
relyingPartyRegistrationResolver(http));
|
||||
openSaml4AuthenticationRequestResolver
|
||||
.setRequestMatcher(new AntPathRequestMatcher(this.authenticationRequestUri));
|
||||
return openSaml4AuthenticationRequestResolver;
|
||||
@@ -346,20 +352,19 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
AuthenticationConverter authenticationConverterBean = getBeanOrNull(http,
|
||||
Saml2AuthenticationTokenConverter.class);
|
||||
if (authenticationConverterBean == null) {
|
||||
authenticationConverterBean = getBeanOrNull(http, OpenSamlAuthenticationTokenConverter.class);
|
||||
}
|
||||
if (authenticationConverterBean == null) {
|
||||
OpenSamlAuthenticationTokenConverter converter = new OpenSamlAuthenticationTokenConverter(
|
||||
this.relyingPartyRegistrationRepository);
|
||||
converter.setAuthenticationRequestRepository(getAuthenticationRequestRepository(http));
|
||||
converter.setRequestMatcher(createLoginProcessingUrlMatcher(this.loginProcessingUrl));
|
||||
return converter;
|
||||
Assert.state(this.loginProcessingUrl.contains("{registrationId}"),
|
||||
"loginProcessingUrl must contain {registrationId} path variable");
|
||||
return new Saml2AuthenticationTokenConverter(
|
||||
new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository));
|
||||
}
|
||||
return authenticationConverterBean;
|
||||
}
|
||||
|
||||
private void registerDefaultAuthenticationProvider(B http) {
|
||||
http.authenticationProvider(postProcess(new OpenSaml4AuthenticationProvider()));
|
||||
OpenSaml4AuthenticationProvider provider = getBeanOrNull(http, OpenSaml4AuthenticationProvider.class);
|
||||
if (provider == null) {
|
||||
http.authenticationProvider(postProcess(new OpenSaml4AuthenticationProvider()));
|
||||
}
|
||||
}
|
||||
|
||||
private void registerDefaultCsrfOverride(B http) {
|
||||
|
||||
+25
-48
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,10 +39,11 @@ import org.springframework.security.saml2.provider.service.authentication.logout
|
||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponseValidator;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutRequestResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSamlLogoutRequestValidatorParametersResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestResolver;
|
||||
@@ -168,13 +169,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* Get configurer for SAML 2.0 Logout Request components
|
||||
* @return the {@link LogoutRequestConfigurer} for further customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #logoutRequest(Customizer)} or
|
||||
* {@code logoutRequest(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public LogoutRequestConfigurer logoutRequest() {
|
||||
return this.logoutRequestConfigurer;
|
||||
}
|
||||
@@ -194,19 +189,13 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* Get configurer for SAML 2.0 Logout Response components
|
||||
* @return the {@link LogoutResponseConfigurer} for further customizations
|
||||
* @deprecated For removal in 7.0. Use {@link #logoutResponse(Customizer)} or
|
||||
* {@code logoutResponse(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public LogoutResponseConfigurer logoutResponse() {
|
||||
return this.logoutResponseConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures SAML 2.0 Logout Response components
|
||||
* Configures SAML 2.0 Logout Request components
|
||||
* @param logoutResponseConfigurerCustomizer the {@link Customizer} to provide more
|
||||
* options for the {@link LogoutResponseConfigurer}
|
||||
* @return the {@link Saml2LogoutConfigurer} for further customizations
|
||||
@@ -227,12 +216,17 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
this.logoutHandlers = logout.getLogoutHandlers();
|
||||
this.logoutSuccessHandler = logout.getLogoutSuccessHandler();
|
||||
}
|
||||
RelyingPartyRegistrationRepository registrations = getRelyingPartyRegistrationRepository(http);
|
||||
RelyingPartyRegistrationResolver registrations = relyingPartyRegistrationResolver(http);
|
||||
http.addFilterBefore(createLogoutRequestProcessingFilter(registrations), CsrfFilter.class);
|
||||
http.addFilterBefore(createLogoutResponseProcessingFilter(registrations), CsrfFilter.class);
|
||||
http.addFilterBefore(createRelyingPartyLogoutFilter(registrations), LogoutFilter.class);
|
||||
}
|
||||
|
||||
private RelyingPartyRegistrationResolver relyingPartyRegistrationResolver(H http) {
|
||||
RelyingPartyRegistrationRepository registrations = getRelyingPartyRegistrationRepository(http);
|
||||
return new DefaultRelyingPartyRegistrationResolver(registrations);
|
||||
}
|
||||
|
||||
private RelyingPartyRegistrationRepository getRelyingPartyRegistrationRepository(H http) {
|
||||
if (this.relyingPartyRegistrationRepository != null) {
|
||||
return this.relyingPartyRegistrationRepository;
|
||||
@@ -248,21 +242,18 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
|
||||
private Saml2LogoutRequestFilter createLogoutRequestProcessingFilter(
|
||||
RelyingPartyRegistrationRepository registrations) {
|
||||
RelyingPartyRegistrationResolver registrations) {
|
||||
LogoutHandler[] logoutHandlers = this.logoutHandlers.toArray(new LogoutHandler[0]);
|
||||
Saml2LogoutResponseResolver logoutResponseResolver = createSaml2LogoutResponseResolver(registrations);
|
||||
RequestMatcher requestMatcher = createLogoutRequestMatcher();
|
||||
OpenSamlLogoutRequestValidatorParametersResolver parameters = new OpenSamlLogoutRequestValidatorParametersResolver(
|
||||
registrations);
|
||||
parameters.setRequestMatcher(requestMatcher);
|
||||
Saml2LogoutRequestFilter filter = new Saml2LogoutRequestFilter(parameters,
|
||||
Saml2LogoutRequestFilter filter = new Saml2LogoutRequestFilter(registrations,
|
||||
this.logoutRequestConfigurer.logoutRequestValidator(), logoutResponseResolver, logoutHandlers);
|
||||
filter.setLogoutRequestMatcher(createLogoutRequestMatcher());
|
||||
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
return postProcess(filter);
|
||||
}
|
||||
|
||||
private Saml2LogoutResponseFilter createLogoutResponseProcessingFilter(
|
||||
RelyingPartyRegistrationRepository registrations) {
|
||||
RelyingPartyRegistrationResolver registrations) {
|
||||
Saml2LogoutResponseFilter logoutResponseFilter = new Saml2LogoutResponseFilter(registrations,
|
||||
this.logoutResponseConfigurer.logoutResponseValidator(), this.logoutSuccessHandler);
|
||||
logoutResponseFilter.setLogoutRequestMatcher(createLogoutResponseMatcher());
|
||||
@@ -270,7 +261,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return postProcess(logoutResponseFilter);
|
||||
}
|
||||
|
||||
private LogoutFilter createRelyingPartyLogoutFilter(RelyingPartyRegistrationRepository registrations) {
|
||||
private LogoutFilter createRelyingPartyLogoutFilter(RelyingPartyRegistrationResolver registrations) {
|
||||
LogoutHandler[] logoutHandlers = this.logoutHandlers.toArray(new LogoutHandler[0]);
|
||||
Saml2RelyingPartyInitiatedLogoutSuccessHandler logoutRequestSuccessHandler = createSaml2LogoutRequestSuccessHandler(
|
||||
registrations);
|
||||
@@ -299,15 +290,15 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
|
||||
private Saml2RelyingPartyInitiatedLogoutSuccessHandler createSaml2LogoutRequestSuccessHandler(
|
||||
RelyingPartyRegistrationRepository registrations) {
|
||||
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
|
||||
Saml2LogoutRequestResolver logoutRequestResolver = this.logoutRequestConfigurer
|
||||
.logoutRequestResolver(registrations);
|
||||
.logoutRequestResolver(relyingPartyRegistrationResolver);
|
||||
return new Saml2RelyingPartyInitiatedLogoutSuccessHandler(logoutRequestResolver);
|
||||
}
|
||||
|
||||
private Saml2LogoutResponseResolver createSaml2LogoutResponseResolver(
|
||||
RelyingPartyRegistrationRepository registrations) {
|
||||
return this.logoutResponseConfigurer.logoutResponseResolver(registrations);
|
||||
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
|
||||
return this.logoutResponseConfigurer.logoutResponseResolver(relyingPartyRegistrationResolver);
|
||||
}
|
||||
|
||||
private <C> C getBeanOrNull(Class<C> clazz) {
|
||||
@@ -383,14 +374,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #logoutRequest(Customizer)} or
|
||||
* {@code logoutRequest(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public Saml2LogoutConfigurer<H> and() {
|
||||
return Saml2LogoutConfigurer.this;
|
||||
}
|
||||
@@ -402,11 +385,12 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this.logoutRequestValidator;
|
||||
}
|
||||
|
||||
private Saml2LogoutRequestResolver logoutRequestResolver(RelyingPartyRegistrationRepository registrations) {
|
||||
private Saml2LogoutRequestResolver logoutRequestResolver(
|
||||
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
|
||||
if (this.logoutRequestResolver != null) {
|
||||
return this.logoutRequestResolver;
|
||||
}
|
||||
return new OpenSaml4LogoutRequestResolver(registrations);
|
||||
return new OpenSaml4LogoutRequestResolver(relyingPartyRegistrationResolver);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -459,14 +443,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #logoutResponse(Customizer)} or
|
||||
* {@code logoutResponse(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public Saml2LogoutConfigurer<H> and() {
|
||||
return Saml2LogoutConfigurer.this;
|
||||
}
|
||||
@@ -478,9 +454,10 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this.logoutResponseValidator;
|
||||
}
|
||||
|
||||
private Saml2LogoutResponseResolver logoutResponseResolver(RelyingPartyRegistrationRepository registrations) {
|
||||
private Saml2LogoutResponseResolver logoutResponseResolver(
|
||||
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
|
||||
if (this.logoutResponseResolver == null) {
|
||||
return new OpenSaml4LogoutResponseResolver(registrations);
|
||||
return new OpenSaml4LogoutResponseResolver(relyingPartyRegistrationResolver);
|
||||
}
|
||||
return this.logoutResponseResolver;
|
||||
}
|
||||
|
||||
-169
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers.saml2;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.saml2.provider.service.metadata.OpenSamlMetadataResolver;
|
||||
import org.springframework.security.saml2.provider.service.metadata.RequestMatcherMetadataResponseResolver;
|
||||
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponseResolver;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.Saml2MetadataFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AbstractHttpConfigurer} for SAML 2.0 Metadata.
|
||||
*
|
||||
* <p>
|
||||
* SAML 2.0 Metadata provides an application with the capability to publish configuration
|
||||
* information as a {@code <md:EntityDescriptor>} or {@code <md:EntitiesDescriptor>}.
|
||||
*
|
||||
* <p>
|
||||
* Defaults are provided for all configuration options with the only required
|
||||
* configuration being a {@link Saml2LoginConfigurer#relyingPartyRegistrationRepository}.
|
||||
* Alternatively, a {@link RelyingPartyRegistrationRepository} {@code @Bean} may be
|
||||
* registered instead.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following {@code Filter} is populated:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link Saml2MetadataFilter}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* none
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link RelyingPartyRegistrationRepository} (required)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 6.1
|
||||
* @see HttpSecurity#saml2Metadata()
|
||||
* @see Saml2MetadataFilter
|
||||
* @see RelyingPartyRegistrationRepository
|
||||
*/
|
||||
public class Saml2MetadataConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractHttpConfigurer<Saml2LogoutConfigurer<H>, H> {
|
||||
|
||||
private final ApplicationContext context;
|
||||
|
||||
private Function<RelyingPartyRegistrationRepository, Saml2MetadataResponseResolver> metadataResponseResolver;
|
||||
|
||||
public Saml2MetadataConfigurer(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this endpoint to request relying party metadata.
|
||||
*
|
||||
* <p>
|
||||
* If you specify a {@code registrationId} placeholder in the URL, then the filter
|
||||
* will lookup a {@link RelyingPartyRegistration} using that.
|
||||
*
|
||||
* <p>
|
||||
* If there is no {@code registrationId} and your
|
||||
* {@link RelyingPartyRegistrationRepository} is {code Iterable}, the metadata
|
||||
* endpoint will try and show all relying parties' metadata in a single
|
||||
* {@code <md:EntitiesDecriptor} element.
|
||||
*
|
||||
* <p>
|
||||
* If you need a more sophisticated lookup strategy than these, use
|
||||
* {@link #metadataResponseResolver} instead.
|
||||
* @param metadataUrl the url to use
|
||||
* @return the {@link Saml2MetadataConfigurer} for more customizations
|
||||
*/
|
||||
public Saml2MetadataConfigurer<H> metadataUrl(String metadataUrl) {
|
||||
Assert.hasText(metadataUrl, "metadataUrl cannot be empty");
|
||||
this.metadataResponseResolver = (registrations) -> {
|
||||
RequestMatcherMetadataResponseResolver metadata = new RequestMatcherMetadataResponseResolver(registrations,
|
||||
new OpenSamlMetadataResolver());
|
||||
metadata.setRequestMatcher(new AntPathRequestMatcher(metadataUrl));
|
||||
return metadata;
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this {@link Saml2MetadataResponseResolver} to parse the request and respond
|
||||
* with SAML 2.0 metadata.
|
||||
* @param metadataResponseResolver to use
|
||||
* @return the {@link Saml2MetadataConfigurer} for more customizations
|
||||
*/
|
||||
public Saml2MetadataConfigurer<H> metadataResponseResolver(Saml2MetadataResponseResolver metadataResponseResolver) {
|
||||
Assert.notNull(metadataResponseResolver, "metadataResponseResolver cannot be null");
|
||||
this.metadataResponseResolver = (registrations) -> metadataResponseResolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
public H and() {
|
||||
return getBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
Saml2MetadataResponseResolver metadataResponseResolver = createMetadataResponseResolver(http);
|
||||
http.addFilterBefore(new Saml2MetadataFilter(metadataResponseResolver), BasicAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
private Saml2MetadataResponseResolver createMetadataResponseResolver(H http) {
|
||||
if (this.metadataResponseResolver != null) {
|
||||
RelyingPartyRegistrationRepository registrations = getRelyingPartyRegistrationRepository(http);
|
||||
return this.metadataResponseResolver.apply(registrations);
|
||||
}
|
||||
Saml2MetadataResponseResolver metadataResponseResolver = getBeanOrNull(Saml2MetadataResponseResolver.class);
|
||||
if (metadataResponseResolver != null) {
|
||||
return metadataResponseResolver;
|
||||
}
|
||||
RelyingPartyRegistrationRepository registrations = getRelyingPartyRegistrationRepository(http);
|
||||
return new RequestMatcherMetadataResponseResolver(registrations, new OpenSamlMetadataResolver());
|
||||
}
|
||||
|
||||
private RelyingPartyRegistrationRepository getRelyingPartyRegistrationRepository(H http) {
|
||||
Saml2LoginConfigurer<H> login = http.getConfigurer(Saml2LoginConfigurer.class);
|
||||
if (login != null) {
|
||||
return login.relyingPartyRegistrationRepository(http);
|
||||
}
|
||||
else {
|
||||
return getBeanOrNull(RelyingPartyRegistrationRepository.class);
|
||||
}
|
||||
}
|
||||
|
||||
private <C> C getBeanOrNull(Class<C> clazz) {
|
||||
if (this.context == null) {
|
||||
return null;
|
||||
}
|
||||
if (this.context.getBeanNamesForType(clazz).length == 0) {
|
||||
return null;
|
||||
}
|
||||
return this.context.getBean(clazz);
|
||||
}
|
||||
|
||||
}
|
||||
+4
-297
@@ -423,13 +423,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link HttpsRedirectSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #redirectToHttps(Customizer)} or
|
||||
* {@code redirectToHttps(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HttpsRedirectSpec redirectToHttps() {
|
||||
this.httpsRedirectSpec = new HttpsRedirectSpec();
|
||||
return this.httpsRedirectSpec;
|
||||
@@ -510,12 +504,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link CsrfSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #csrf(Customizer)} or
|
||||
* {@code csrf(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CsrfSpec csrf() {
|
||||
if (this.csrf == null) {
|
||||
this.csrf = new CsrfSpec();
|
||||
@@ -579,12 +568,7 @@ public class ServerHttpSecurity {
|
||||
* used instead. If neither has been configured, the Cors configuration will do
|
||||
* nothing.
|
||||
* @return the {@link CorsSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #cors(Customizer)} or
|
||||
* {@code cors(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CorsSpec cors() {
|
||||
if (this.cors == null) {
|
||||
this.cors = new CorsSpec();
|
||||
@@ -626,13 +610,7 @@ public class ServerHttpSecurity {
|
||||
* </pre>
|
||||
* @return the {@link AnonymousSpec} to customize
|
||||
* @since 5.2.0
|
||||
* @deprecated For removal in 7.0. Use {@link #anonymous(Customizer)} or
|
||||
* {@code anonymous(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AnonymousSpec anonymous() {
|
||||
if (this.anonymous == null) {
|
||||
this.anonymous = new AnonymousSpec();
|
||||
@@ -686,13 +664,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link HttpBasicSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #httpBasic(Customizer)} or
|
||||
* {@code httpBasic(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HttpBasicSpec httpBasic() {
|
||||
if (this.httpBasic == null) {
|
||||
this.httpBasic = new HttpBasicSpec();
|
||||
@@ -744,13 +716,7 @@ public class ServerHttpSecurity {
|
||||
* </pre>
|
||||
* @return the {@link PasswordManagementSpec} to customize
|
||||
* @since 5.6
|
||||
* @deprecated For removal in 7.0. Use {@link #passwordManagement(Customizer)} or
|
||||
* {@code passwordManagement(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public PasswordManagementSpec passwordManagement() {
|
||||
if (this.passwordManagement == null) {
|
||||
this.passwordManagement = new PasswordManagementSpec();
|
||||
@@ -807,13 +773,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link FormLoginSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #formLogin(Customizer)} or
|
||||
* {@code formLogin(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public FormLoginSpec formLogin() {
|
||||
if (this.formLogin == null) {
|
||||
this.formLogin = new FormLoginSpec();
|
||||
@@ -874,12 +834,7 @@ public class ServerHttpSecurity {
|
||||
* {@link ReactivePreAuthenticatedAuthenticationManager} will be used.
|
||||
* @return the {@link X509Spec} to customize
|
||||
* @since 5.2
|
||||
* @deprecated For removal in 7.0. Use {@link #x509(Customizer)} or
|
||||
* {@code x509(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public X509Spec x509() {
|
||||
if (this.x509 == null) {
|
||||
this.x509 = new X509Spec();
|
||||
@@ -936,13 +891,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link OAuth2LoginSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #oauth2Login(Customizer)} or
|
||||
* {@code oauth2Login(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2LoginSpec oauth2Login() {
|
||||
if (this.oauth2Login == null) {
|
||||
this.oauth2Login = new OAuth2LoginSpec();
|
||||
@@ -994,13 +943,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link OAuth2ClientSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #oauth2Client(Customizer)} or
|
||||
* {@code oauth2Client(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ClientSpec oauth2Client() {
|
||||
if (this.client == null) {
|
||||
this.client = new OAuth2ClientSpec();
|
||||
@@ -1051,10 +994,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link OAuth2ResourceServerSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #oauth2ResourceServer(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ResourceServerSpec oauth2ResourceServer() {
|
||||
if (this.resourceServer == null) {
|
||||
this.resourceServer = new OAuth2ResourceServerSpec();
|
||||
@@ -1126,12 +1066,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link HeaderSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #headers(Customizer)} or
|
||||
* {@code headers(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec headers() {
|
||||
if (this.headers == null) {
|
||||
this.headers = new HeaderSpec();
|
||||
@@ -1205,13 +1140,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link ExceptionHandlingSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #exceptionHandling(Customizer)} or
|
||||
* {@code exceptionHandling(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ExceptionHandlingSpec exceptionHandling() {
|
||||
if (this.exceptionHandling == null) {
|
||||
this.exceptionHandling = new ExceptionHandlingSpec();
|
||||
@@ -1277,13 +1206,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link AuthorizeExchangeSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizeExchange(Customizer)} or
|
||||
* {@code authorizeExchange(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public AuthorizeExchangeSpec authorizeExchange() {
|
||||
if (this.authorizeExchange == null) {
|
||||
this.authorizeExchange = new AuthorizeExchangeSpec();
|
||||
@@ -1352,12 +1275,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link LogoutSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #logout(Customizer)} or
|
||||
* {@code logout(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public LogoutSpec logout() {
|
||||
if (this.logout == null) {
|
||||
this.logout = new LogoutSpec();
|
||||
@@ -1414,13 +1332,7 @@ public class ServerHttpSecurity {
|
||||
* }
|
||||
* </pre>
|
||||
* @return the {@link RequestCacheSpec} to customize
|
||||
* @deprecated For removal in 7.0. Use {@link #requestCache(Customizer)} or
|
||||
* {@code requestCache(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public RequestCacheSpec requestCache() {
|
||||
return this.requestCache;
|
||||
}
|
||||
@@ -1709,10 +1621,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #authorizeExchange(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -1926,9 +1835,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated use {@link #redirectToHttps(Customizer)}
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -2006,13 +1913,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #csrf(Customizer)} or
|
||||
* {@code csrf(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -2078,10 +1979,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #exceptionHandling(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -2123,13 +2021,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #requestCache(Customizer)} or
|
||||
* {@code requestCache(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -2225,13 +2117,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #httpBasic(Customizer)} or
|
||||
* {@code httpBasic(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -2304,10 +2190,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}.
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #passwordManagement(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -2465,13 +2348,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #formLogin(Customizer)} or
|
||||
* {@code formLogin(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -2595,13 +2472,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #headers(Customizer)} or
|
||||
* {@code headers(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -2618,13 +2489,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures cache control headers
|
||||
* @return the {@link CacheSpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #cache(Customizer)} or
|
||||
* {@code cache(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CacheSpec cache() {
|
||||
return new CacheSpec();
|
||||
}
|
||||
@@ -2643,10 +2508,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures content type response headers
|
||||
* @return the {@link ContentTypeOptionsSpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ContentTypeOptionsSpec contentTypeOptions() {
|
||||
return new ContentTypeOptionsSpec();
|
||||
}
|
||||
@@ -2665,13 +2527,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures frame options response headers
|
||||
* @return the {@link FrameOptionsSpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or
|
||||
* {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public FrameOptionsSpec frameOptions() {
|
||||
return new FrameOptionsSpec();
|
||||
}
|
||||
@@ -2703,13 +2559,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures the Strict Transport Security response headers
|
||||
* @return the {@link HstsSpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #hsts(Customizer)} or
|
||||
* {@code hsts(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HstsSpec hsts() {
|
||||
return new HstsSpec();
|
||||
}
|
||||
@@ -2734,13 +2584,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures x-xss-protection response header.
|
||||
* @return the {@link XssProtectionSpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or
|
||||
* {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See
|
||||
* the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public XssProtectionSpec xssProtection() {
|
||||
return new XssProtectionSpec();
|
||||
}
|
||||
@@ -2760,10 +2604,7 @@ public class ServerHttpSecurity {
|
||||
* Configures {@code Content-Security-Policy} response header.
|
||||
* @param policyDirectives the policy directive(s)
|
||||
* @return the {@link ContentSecurityPolicySpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ContentSecurityPolicySpec contentSecurityPolicy(String policyDirectives) {
|
||||
return new ContentSecurityPolicySpec(policyDirectives);
|
||||
}
|
||||
@@ -2783,8 +2624,7 @@ public class ServerHttpSecurity {
|
||||
* Configures {@code Feature-Policy} response header.
|
||||
* @param policyDirectives the policy
|
||||
* @return the {@link FeaturePolicySpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)}
|
||||
* instead.
|
||||
* @deprecated Use {@link #permissionsPolicy(Customizer)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public FeaturePolicySpec featurePolicy(String policyDirectives) {
|
||||
@@ -2794,10 +2634,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures {@code Permissions-Policy} response header.
|
||||
* @return the {@link PermissionsPolicySpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public PermissionsPolicySpec permissionsPolicy() {
|
||||
return new PermissionsPolicySpec();
|
||||
}
|
||||
@@ -2817,10 +2654,7 @@ public class ServerHttpSecurity {
|
||||
* Configures {@code Referrer-Policy} response header.
|
||||
* @param referrerPolicy the policy to use
|
||||
* @return the {@link ReferrerPolicySpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ReferrerPolicySpec referrerPolicy(ReferrerPolicy referrerPolicy) {
|
||||
return new ReferrerPolicySpec(referrerPolicy);
|
||||
}
|
||||
@@ -2828,10 +2662,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures {@code Referrer-Policy} response header.
|
||||
* @return the {@link ReferrerPolicySpec} to configure
|
||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ReferrerPolicySpec referrerPolicy() {
|
||||
return new ReferrerPolicySpec();
|
||||
}
|
||||
@@ -2853,11 +2684,8 @@ public class ServerHttpSecurity {
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
* @return the {@link CrossOriginOpenerPolicySpec} to configure
|
||||
* @since 5.7
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginOpenerPolicy(Customizer)} instead.
|
||||
* @see CrossOriginOpenerPolicyServerHttpHeadersWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CrossOriginOpenerPolicySpec crossOriginOpenerPolicy() {
|
||||
return new CrossOriginOpenerPolicySpec();
|
||||
}
|
||||
@@ -2882,11 +2710,8 @@ public class ServerHttpSecurity {
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
* @return the {@link CrossOriginEmbedderPolicySpec} to configure
|
||||
* @since 5.7
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginEmbedderPolicy(Customizer)} instead.
|
||||
* @see CrossOriginEmbedderPolicyServerHttpHeadersWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CrossOriginEmbedderPolicySpec crossOriginEmbedderPolicy() {
|
||||
return new CrossOriginEmbedderPolicySpec();
|
||||
}
|
||||
@@ -2911,11 +2736,8 @@ public class ServerHttpSecurity {
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
* @return the {@link CrossOriginResourcePolicySpec} to configure
|
||||
* @since 5.7
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginResourcePolicy(Customizer)} instead.
|
||||
* @see CrossOriginResourcePolicyServerHttpHeadersWriter
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public CrossOriginResourcePolicySpec crossOriginResourcePolicy() {
|
||||
return new CrossOriginResourcePolicySpec();
|
||||
}
|
||||
@@ -3001,10 +2823,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
private HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
@@ -3072,13 +2891,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #hsts(Customizer)} or
|
||||
* {@code hsts(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
@@ -3167,10 +2980,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #contentSecurityPolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
@@ -3197,10 +3007,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #featurePolicy(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
@@ -3232,10 +3039,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
@@ -3272,10 +3076,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
@@ -3306,10 +3107,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginOpenerPolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
@@ -3340,10 +3138,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginEmbedderPolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
@@ -3374,10 +3169,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use
|
||||
* {@link #crossOriginResourcePolicy(Customizer)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
@@ -3453,13 +3245,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #logout(Customizer)} or
|
||||
* {@code logout(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -3570,13 +3356,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #cors(Customizer)} or
|
||||
* {@code cors(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -3632,14 +3412,6 @@ public class ServerHttpSecurity {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #x509(Customizer)} or
|
||||
* {@code x509(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -3892,13 +3664,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #oauth2Login(Customizer)} or
|
||||
* {@code oauth2Login(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -4097,8 +3863,6 @@ public class ServerHttpSecurity {
|
||||
|
||||
private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
|
||||
|
||||
private ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver;
|
||||
|
||||
private ServerRedirectStrategy authorizationRedirectStrategy;
|
||||
|
||||
private OAuth2ClientSpec() {
|
||||
@@ -4193,26 +3957,6 @@ public class ServerHttpSecurity {
|
||||
return this.authorizationRequestRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resolver used for resolving {@link OAuth2AuthorizationRequest}'s.
|
||||
* @param authorizationRequestResolver the resolver used for resolving
|
||||
* {@link OAuth2AuthorizationRequest}'s
|
||||
* @return the {@link OAuth2ClientSpec} to customize
|
||||
* @since 6.1
|
||||
*/
|
||||
public OAuth2ClientSpec authorizationRequestResolver(
|
||||
ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver) {
|
||||
this.authorizationRequestResolver = authorizationRequestResolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
private OAuth2AuthorizationRequestRedirectWebFilter getRedirectWebFilter() {
|
||||
if (this.authorizationRequestResolver != null) {
|
||||
return new OAuth2AuthorizationRequestRedirectWebFilter(this.authorizationRequestResolver);
|
||||
}
|
||||
return new OAuth2AuthorizationRequestRedirectWebFilter(getClientRegistrationRepository());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the redirect strategy for Authorization Endpoint redirect URI.
|
||||
* @param authorizationRedirectStrategy the redirect strategy
|
||||
@@ -4233,18 +3977,13 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #oauth2Client(Customizer)} or
|
||||
* {@code oauth2Client(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
|
||||
protected void configure(ServerHttpSecurity http) {
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository();
|
||||
ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository();
|
||||
ServerAuthenticationConverter authenticationConverter = getAuthenticationConverter();
|
||||
ReactiveAuthenticationManager authenticationManager = getAuthenticationManager();
|
||||
@@ -4255,7 +3994,8 @@ public class ServerHttpSecurity {
|
||||
codeGrantWebFilter.setRequestCache(http.requestCache.requestCache);
|
||||
}
|
||||
|
||||
OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = getRedirectWebFilter();
|
||||
OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter(
|
||||
clientRegistrationRepository);
|
||||
oauthRedirectFilter.setAuthorizationRequestRepository(getAuthorizationRequestRepository());
|
||||
oauthRedirectFilter.setAuthorizationRedirectStrategy(getAuthorizationRedirectStrategy());
|
||||
if (http.requestCache != null) {
|
||||
@@ -4387,12 +4127,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Enables JWT Resource Server support.
|
||||
* @return the {@link JwtSpec} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
|
||||
* {@code jwt(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public JwtSpec jwt() {
|
||||
if (this.jwt == null) {
|
||||
this.jwt = new JwtSpec();
|
||||
@@ -4417,13 +4152,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Enables Opaque Token Resource Server support.
|
||||
* @return the {@link OpaqueTokenSpec} for additional configuration
|
||||
* @deprecated For removal in 7.0. Use {@link #opaqueToken(Customizer)} or
|
||||
* {@code opaqueToken(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OpaqueTokenSpec opaqueToken() {
|
||||
if (this.opaqueToken == null) {
|
||||
this.opaqueToken = new OpaqueTokenSpec();
|
||||
@@ -4515,11 +4244,6 @@ public class ServerHttpSecurity {
|
||||
return new ServerAuthenticationEntryPointFailureHandler(this.entryPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #oauth2ResourceServer(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
@@ -4593,14 +4317,6 @@ public class ServerHttpSecurity {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
|
||||
* {@code jwt(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ResourceServerSpec and() {
|
||||
return OAuth2ResourceServerSpec.this;
|
||||
}
|
||||
@@ -4711,10 +4427,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #opaqueToken(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public OAuth2ResourceServerSpec and() {
|
||||
return OAuth2ResourceServerSpec.this;
|
||||
}
|
||||
@@ -4840,13 +4553,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #anonymous(Customizer)} or
|
||||
* {@code anonymous(Customizer.withDefaults())} to stick with defaults. See the
|
||||
* <a href=
|
||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
||||
* for more details.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public ServerHttpSecurity and() {
|
||||
return ServerHttpSecurity.this;
|
||||
}
|
||||
|
||||
+1
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -51,17 +51,6 @@ class FormLoginDsl {
|
||||
|
||||
private var defaultSuccessUrlOption: Pair<String, Boolean>? = null
|
||||
|
||||
private var disabled = false
|
||||
|
||||
/**
|
||||
* Disable FormLogin.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
fun disable() {
|
||||
disabled = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants access to the urls for [failureUrl] as well as for the [HttpSecurityBuilder], the
|
||||
* [loginPage] and [loginProcessingUrl] for every user.
|
||||
@@ -95,9 +84,6 @@ class FormLoginDsl {
|
||||
authenticationSuccessHandler?.also { login.successHandler(authenticationSuccessHandler) }
|
||||
authenticationFailureHandler?.also { login.failureHandler(authenticationFailureHandler) }
|
||||
authenticationDetailsSource?.also { login.authenticationDetailsSource(authenticationDetailsSource) }
|
||||
if (disabled) {
|
||||
login.disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-37
@@ -677,43 +677,6 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
|
||||
this.http.saml2Login(saml2LoginCustomizer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a SAML 2.0 relying party metadata endpoint.
|
||||
*
|
||||
* A [RelyingPartyRegistrationRepository] is required and must be registered with
|
||||
* the [ApplicationContext] or configured via
|
||||
* [Saml2Dsl.relyingPartyRegistrationRepository]
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* The following example shows the minimal configuration required, using a
|
||||
* hypothetical asserting party.
|
||||
*
|
||||
* ```
|
||||
* @Configuration
|
||||
* @EnableWebSecurity
|
||||
* class SecurityConfig {
|
||||
*
|
||||
* @Bean
|
||||
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
* http {
|
||||
* saml2Login { }
|
||||
* saml2Metadata { }
|
||||
* }
|
||||
* return http.build()
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @param saml2MetadataConfiguration custom configuration to configure the
|
||||
* SAML2 relying party metadata endpoint
|
||||
* @see [Saml2MetadataDsl]
|
||||
* @since 6.1
|
||||
*/
|
||||
fun saml2Metadata(saml2MetadataConfiguration: Saml2MetadataDsl.() -> Unit) {
|
||||
val saml2MetadataCustomizer = Saml2MetadataDsl().apply(saml2MetadataConfiguration).get()
|
||||
this.http.saml2Metadata(saml2MetadataCustomizer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuring how an anonymous user is represented.
|
||||
*
|
||||
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManagerResolver
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.oauth2.resourceserver.JwtDsl
|
||||
import org.springframework.security.config.annotation.web.oauth2.resourceserver.OpaqueTokenDsl
|
||||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.access.AccessDeniedHandler
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.springframework.security.config.annotation.web.configurers.saml2.Saml2MetadataConfigurer
|
||||
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponseResolver
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure [HttpSecurity] SAML 2.0 relying party metadata support using
|
||||
* idiomatic Kotlin code.
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 6.1
|
||||
* @property metadataUrl the name of the relying party metadata endpoint; defaults to `/saml2/metadata` and `/saml2/metadata/{registrationId}`
|
||||
* @property metadataResponseResolver the [Saml2MetadataResponseResolver] to use for resolving the
|
||||
* metadata request into metadata
|
||||
*/
|
||||
@SecurityMarker
|
||||
class Saml2MetadataDsl {
|
||||
var metadataUrl: String? = null
|
||||
var metadataResponseResolver: Saml2MetadataResponseResolver? = null
|
||||
|
||||
internal fun get(): (Saml2MetadataConfigurer<HttpSecurity>) -> Unit {
|
||||
return { saml2Metadata ->
|
||||
metadataResponseResolver?.also { saml2Metadata.metadataResponseResolver(metadataResponseResolver) }
|
||||
metadataUrl?.also { saml2Metadata.metadataUrl(metadataUrl) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-6.1.xsd=org/springframework/security/config/spring-security-6.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.0.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-6.0.xsd=org/springframework/security/config/spring-security-6.0.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-5.8.xsd=org/springframework/security/config/spring-security-5.8.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-5.7.xsd=org/springframework/security/config/spring-security-5.7.xsd
|
||||
@@ -21,8 +20,7 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.1.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-6.1.xsd=org/springframework/security/config/spring-security-6.1.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.0.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-6.0.xsd=org/springframework/security/config/spring-security-6.0.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-5.8.xsd=org/springframework/security/config/spring-security-5.8.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-5.7.xsd=org/springframework/security/config/spring-security-5.7.xsd
|
||||
|
||||
-1346
File diff suppressed because it is too large
Load Diff
-3812
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
spring-security-6.1.xsd
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -35,7 +37,7 @@ public class MockServletContext extends org.springframework.mock.web.MockServlet
|
||||
|
||||
public static MockServletContext mvc() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class);
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
@@ -59,6 +61,8 @@ public class MockServletContext extends org.springframework.mock.web.MockServlet
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
private final Set<String> mappings = new LinkedHashSet<>();
|
||||
|
||||
MockServletRegistration(String name, Class<?> clazz) {
|
||||
this.name = name;
|
||||
this.clazz = clazz;
|
||||
@@ -91,12 +95,13 @@ public class MockServletContext extends org.springframework.mock.web.MockServlet
|
||||
|
||||
@Override
|
||||
public Set<String> addMapping(String... urlPatterns) {
|
||||
return null;
|
||||
this.mappings.addAll(Arrays.asList(urlPatterns));
|
||||
return this.mappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getMappings() {
|
||||
return null;
|
||||
return this.mappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+15
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@ import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
@@ -64,6 +65,8 @@ import org.springframework.security.test.context.support.WithSecurityContextTest
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -418,6 +421,17 @@ public class PrePostMethodSecurityConfigurationTests {
|
||||
assertThat(this.spring.getContext().containsBean("annotationSecurityAspect$0")).isFalse();
|
||||
}
|
||||
|
||||
// gh-13572
|
||||
@Test
|
||||
public void configureWhenBeanOverridingDisallowedThenWorks() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class, BusinessServiceConfig.class)
|
||||
.postProcessor(disallowBeanOverriding()).autowire();
|
||||
}
|
||||
|
||||
private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() {
|
||||
return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableMethodSecurity
|
||||
static class MethodSecurityServiceConfig {
|
||||
|
||||
+14
-2
@@ -174,12 +174,24 @@ public class AbstractRequestMatcherRegistryTests {
|
||||
public void requestMatchersWhenAmbiguousServletsThenException() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class);
|
||||
servletContext.addServlet("servletTwo", Servlet.class);
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
|
||||
servletContext.addServlet("servletTwo", Servlet.class).addMapping("/servlet/**");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> this.matcherRegistry.requestMatchers("/**"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenUnmappableServletsThenSkips() {
|
||||
mockMvcIntrospector(true);
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
|
||||
servletContext.addServlet("servletTwo", Servlet.class);
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
|
||||
}
|
||||
|
||||
private void mockMvcIntrospector(boolean isPresent) {
|
||||
ApplicationContext context = this.matcherRegistry.getApplicationContext();
|
||||
given(context.containsBean("mvcHandlerMappingIntrospector")).willReturn(isPresent);
|
||||
|
||||
-32
@@ -20,8 +20,6 @@ import java.io.IOException;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -31,7 +29,6 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.cas.web.CasAuthenticationFilter;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
@@ -45,9 +42,6 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -74,16 +68,6 @@ public class HttpConfigurationTests {
|
||||
+ " Consider using addFilterBefore or addFilterAfter instead.");
|
||||
}
|
||||
|
||||
// https://github.com/spring-projects/spring-security-javaconfig/issues/104
|
||||
@Test
|
||||
public void configureWhenAddFilterCasAuthenticationFilterThenFilterAdded() throws Exception {
|
||||
CasAuthenticationFilterConfig.CAS_AUTHENTICATION_FILTER = spy(new CasAuthenticationFilter());
|
||||
this.spring.register(CasAuthenticationFilterConfig.class).autowire();
|
||||
this.mockMvc.perform(get("/"));
|
||||
verify(CasAuthenticationFilterConfig.CAS_AUTHENTICATION_FILTER).doFilter(any(ServletRequest.class),
|
||||
any(ServletResponse.class), any(FilterChain.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenConfigIsRequestMatchersJavadocThenAuthorizationApplied() throws Exception {
|
||||
this.spring.register(RequestMatcherRegistryConfigs.class).autowire();
|
||||
@@ -123,22 +107,6 @@ public class HttpConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CasAuthenticationFilterConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.addFilter(CAS_AUTHENTICATION_FILTER);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
static CasAuthenticationFilter CAS_AUTHENTICATION_FILTER;
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
|
||||
+1
-38
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,8 +26,6 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
@@ -274,17 +272,6 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
this.mvc.perform(requestWithAdmin).andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenHasRoleUserAndRoleHierarchyConfiguredThenGreaterRoleTakesPrecedence() throws Exception {
|
||||
this.spring.register(RoleHierarchyUserConfig.class, BasicController.class).autowire();
|
||||
// @formatter:off
|
||||
MockHttpServletRequestBuilder requestWithAdmin = get("/")
|
||||
.with(user("user")
|
||||
.roles("ADMIN"));
|
||||
// @formatter:on
|
||||
this.mvc.perform(requestWithAdmin).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenRoleUserOrAdminConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception {
|
||||
this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire();
|
||||
@@ -783,30 +770,6 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class RoleHierarchyUserConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
return http
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.anyRequest().hasRole("USER")
|
||||
)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
RoleHierarchy roleHierarchy() {
|
||||
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
|
||||
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
|
||||
return roleHierarchy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class RoleUserOrAdminConfig {
|
||||
|
||||
+1
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,7 +34,6 @@ import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextChangedListener;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
@@ -43,7 +42,6 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -68,7 +66,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Eleftheria Stein
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class HttpBasicConfigurerTests {
|
||||
@@ -148,15 +145,6 @@ public class HttpBasicConfigurerTests {
|
||||
verify(listener).securityContextChanged(setAuthentication(UsernamePasswordAuthenticationToken.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpBasicWhenUsingCustomSecurityContextRepositoryThenUses() throws Exception {
|
||||
this.spring.register(CustomSecurityContextRepositoryConfig.class, Users.class, Home.class).autowire();
|
||||
this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isOk())
|
||||
.andExpect(content().string("user"));
|
||||
verify(CustomSecurityContextRepositoryConfig.SECURITY_CONTEXT_REPOSITORY)
|
||||
.saveContext(any(SecurityContext.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class ObjectPostProcessorConfig {
|
||||
@@ -333,24 +321,6 @@ public class HttpBasicConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class CustomSecurityContextRepositoryConfig {
|
||||
|
||||
static final SecurityContextRepository SECURITY_CONTEXT_REPOSITORY = mock(SecurityContextRepository.class);
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic()
|
||||
.securityContextRepository(SECURITY_CONTEXT_REPOSITORY);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Users {
|
||||
|
||||
|
||||
+42
-3
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -42,6 +43,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
|
||||
@@ -59,6 +61,7 @@ import org.springframework.security.saml2.core.Saml2ErrorCodes;
|
||||
import org.springframework.security.saml2.core.Saml2Utils;
|
||||
import org.springframework.security.saml2.core.TestSaml2X509Credentials;
|
||||
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
|
||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||
@@ -90,6 +93,7 @@ import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
@@ -306,9 +310,12 @@ public class Saml2LoginConfigurerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saml2LoginWhenLoginProcessingUrlWithoutRegistrationIdAndDefaultAuthenticationConverterThenAutowires()
|
||||
throws Exception {
|
||||
this.spring.register(CustomLoginProcessingUrlDefaultAuthenticationConverter.class).autowire();
|
||||
public void saml2LoginWhenLoginProcessingUrlWithoutRegistrationIdAndDefaultAuthenticationConverterThenValidates() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(CustomLoginProcessingUrlDefaultAuthenticationConverter.class)
|
||||
.autowire())
|
||||
.havingRootCause().isInstanceOf(IllegalStateException.class)
|
||||
.withMessage("loginProcessingUrl must contain {registrationId} path variable");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -353,6 +360,15 @@ public class Saml2LoginConfigurerTests {
|
||||
.andExpect(redirectedUrl("http://localhost/saml2/authenticate/registration-id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saml2LoginWhenCustomAuthenticationProviderThenUses() throws Exception {
|
||||
this.spring.register(CustomAuthenticationProviderConfig.class).autowire();
|
||||
AuthenticationProvider provider = this.spring.getContext().getBean(AuthenticationProvider.class);
|
||||
this.mvc.perform(post("/login/saml2/sso/registration-id").param("SAMLResponse", SIGNED_RESPONSE))
|
||||
.andExpect(status().isFound());
|
||||
verify(provider).authenticate(any());
|
||||
}
|
||||
|
||||
private void performSaml2Login(String expected) throws IOException, ServletException {
|
||||
// setup authentication parameters
|
||||
this.request.setRequestURI("/login/saml2/sso/registration-id");
|
||||
@@ -663,6 +679,29 @@ public class Saml2LoginConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
@Import(Saml2LoginConfigBeans.class)
|
||||
static class CustomAuthenticationProviderConfig {
|
||||
|
||||
private final OpenSaml4AuthenticationProvider provider = spy(new OpenSaml4AuthenticationProvider());
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain web(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.saml2Login(Customizer.withDefaults());
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationProvider provider() {
|
||||
return this.provider;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Saml2LoginConfigBeans {
|
||||
|
||||
@Bean
|
||||
|
||||
-210
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers.saml2;
|
||||
|
||||
import com.google.common.net.HttpHeaders;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.saml2.provider.service.metadata.OpenSamlMetadataResolver;
|
||||
import org.springframework.security.saml2.provider.service.metadata.RequestMatcherMetadataResponseResolver;
|
||||
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponse;
|
||||
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponseResolver;
|
||||
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests for {@link Saml2MetadataConfigurer}
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class Saml2MetadataConfigurerTests {
|
||||
|
||||
static RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration().build();
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired(required = false)
|
||||
MockMvc mvc;
|
||||
|
||||
@Test
|
||||
void saml2MetadataRegistrationIdWhenDefaultsThenReturnsMetadata() throws Exception {
|
||||
this.spring.register(DefaultConfig.class).autowire();
|
||||
String filename = "saml-" + registration.getRegistrationId() + "-metadata.xml";
|
||||
this.mvc.perform(get("/saml2/metadata/" + registration.getRegistrationId())).andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, containsString(filename)))
|
||||
.andExpect(content().string(containsString("md:EntityDescriptor")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void saml2MetadataRegistrationIdWhenWrongIdThenUnauthorized() throws Exception {
|
||||
this.spring.register(DefaultConfig.class).autowire();
|
||||
this.mvc.perform(get("/saml2/metadata/" + registration.getRegistrationId() + "wrong"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
void saml2MetadataWhenDefaultsThenReturnsMetadata() throws Exception {
|
||||
this.spring.register(DefaultConfig.class).autowire();
|
||||
this.mvc.perform(get("/saml2/metadata")).andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, containsString("-metadata.xml")))
|
||||
.andExpect(content().string(containsString("md:EntityDescriptor")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void saml2MetadataWhenMetadataResponseResolverThenUses() throws Exception {
|
||||
this.spring.register(DefaultConfig.class, MetadataResponseResolverConfig.class).autowire();
|
||||
Saml2MetadataResponseResolver metadataResponseResolver = this.spring.getContext()
|
||||
.getBean(Saml2MetadataResponseResolver.class);
|
||||
given(metadataResponseResolver.resolve(any(HttpServletRequest.class)))
|
||||
.willReturn(new Saml2MetadataResponse("metadata", "filename"));
|
||||
this.mvc.perform(get("/saml2/metadata")).andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, containsString("filename")))
|
||||
.andExpect(content().string(containsString("metadata")));
|
||||
verify(metadataResponseResolver).resolve(any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void saml2MetadataWhenMetadataResponseResolverDslThenUses() throws Exception {
|
||||
this.spring.register(MetadataResponseResolverDslConfig.class).autowire();
|
||||
this.mvc.perform(get("/saml2/metadata")).andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, containsString("filename")))
|
||||
.andExpect(content().string(containsString("metadata")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void saml2MetadataWhenMetadataUrlThenUses() throws Exception {
|
||||
this.spring.register(MetadataUrlConfig.class).autowire();
|
||||
String filename = "saml-" + registration.getRegistrationId() + "-metadata.xml";
|
||||
this.mvc.perform(get("/saml/metadata")).andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, containsString(filename)))
|
||||
.andExpect(content().string(containsString("md:EntityDescriptor")));
|
||||
this.mvc.perform(get("/saml2/metadata")).andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@Import(RelyingPartyRegistrationConfig.class)
|
||||
static class DefaultConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filters(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.saml2Metadata(Customizer.withDefaults());
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@Import(RelyingPartyRegistrationConfig.class)
|
||||
static class MetadataUrlConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filters(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.saml2Metadata((saml2) -> saml2.metadataUrl("/saml/metadata"));
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// should ignore
|
||||
@Bean
|
||||
Saml2MetadataResponseResolver metadataResponseResolver(RelyingPartyRegistrationRepository registrations) {
|
||||
return new RequestMatcherMetadataResponseResolver(registrations, new OpenSamlMetadataResolver());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@Import(RelyingPartyRegistrationConfig.class)
|
||||
static class MetadataResponseResolverDslConfig {
|
||||
|
||||
Saml2MetadataResponseResolver metadataResponseResolver = mock(Saml2MetadataResponseResolver.class);
|
||||
|
||||
{
|
||||
given(this.metadataResponseResolver.resolve(any(HttpServletRequest.class)))
|
||||
.willReturn(new Saml2MetadataResponse("metadata", "filename"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filters(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.saml2Metadata((saml2) -> saml2.metadataResponseResolver(this.metadataResponseResolver));
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MetadataResponseResolverConfig {
|
||||
|
||||
Saml2MetadataResponseResolver metadataResponseResolver = mock(Saml2MetadataResponseResolver.class);
|
||||
|
||||
@Bean
|
||||
Saml2MetadataResponseResolver metadataResponseResolver() {
|
||||
return this.metadataResponseResolver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RelyingPartyRegistrationConfig {
|
||||
|
||||
RelyingPartyRegistrationRepository registrations = new InMemoryRelyingPartyRegistrationRepository(registration);
|
||||
|
||||
@Bean
|
||||
RelyingPartyRegistrationRepository registrations() {
|
||||
return this.registrations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -65,7 +65,7 @@ public class XsdDocumentedTests {
|
||||
|
||||
String schema31xDocumentLocation = "org/springframework/security/config/spring-security-3.1.xsd";
|
||||
|
||||
String schemaDocumentLocation = "org/springframework/security/config/spring-security-6.1.xsd";
|
||||
String schemaDocumentLocation = "org/springframework/security/config/spring-security-6.0.xsd";
|
||||
|
||||
XmlSupport xml = new XmlSupport();
|
||||
|
||||
@@ -150,8 +150,8 @@ public class XsdDocumentedTests {
|
||||
.getParentFile()
|
||||
.list((dir, name) -> name.endsWith(".xsd"));
|
||||
// @formatter:on
|
||||
assertThat(schemas.length)
|
||||
.withFailMessage("the count is equal to 23, if not then schemaDocument needs updating").isEqualTo(23);
|
||||
assertThat(schemas.length).isEqualTo(22)
|
||||
.withFailMessage("the count is equal to 22, if not then schemaDocument needs updating");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,6 @@ import org.springframework.security.oauth2.client.registration.InMemoryReactiveC
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizationRequestResolver;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
|
||||
@@ -134,7 +133,6 @@ public class OAuth2ClientSpecTests {
|
||||
ServerAuthenticationConverter converter = config.authenticationConverter;
|
||||
ReactiveAuthenticationManager manager = config.manager;
|
||||
ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = config.authorizationRequestRepository;
|
||||
ServerOAuth2AuthorizationRequestResolver resolver = config.resolver;
|
||||
ServerRequestCache requestCache = config.requestCache;
|
||||
OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
|
||||
.redirectUri("/authorize/oauth2/code/registration-id").build();
|
||||
@@ -147,7 +145,6 @@ public class OAuth2ClientSpecTests {
|
||||
this.registration, authorizationExchange, accessToken);
|
||||
given(authorizationRequestRepository.loadAuthorizationRequest(any()))
|
||||
.willReturn(Mono.just(authorizationRequest));
|
||||
given(resolver.resolve(any())).willReturn(Mono.empty());
|
||||
given(converter.convert(any())).willReturn(Mono.just(new TestingAuthenticationToken("a", "b", "c")));
|
||||
given(manager.authenticate(any())).willReturn(Mono.just(result));
|
||||
given(requestCache.getRedirectUri(any())).willReturn(Mono.just(URI.create("/saved-request")));
|
||||
@@ -165,7 +162,6 @@ public class OAuth2ClientSpecTests {
|
||||
verify(converter).convert(any());
|
||||
verify(manager).authenticate(any());
|
||||
verify(requestCache).getRedirectUri(any());
|
||||
verify(resolver).resolve(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -268,8 +264,6 @@ public class OAuth2ClientSpecTests {
|
||||
ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = mock(
|
||||
ServerAuthorizationRequestRepository.class);
|
||||
|
||||
ServerOAuth2AuthorizationRequestResolver resolver = mock(ServerOAuth2AuthorizationRequestResolver.class);
|
||||
|
||||
ServerRequestCache requestCache = mock(ServerRequestCache.class);
|
||||
|
||||
@Bean
|
||||
@@ -280,7 +274,6 @@ public class OAuth2ClientSpecTests {
|
||||
.authenticationConverter(this.authenticationConverter)
|
||||
.authenticationManager(this.manager)
|
||||
.authorizationRequestRepository(this.authorizationRequestRepository)
|
||||
.authorizationRequestResolver(this.resolver)
|
||||
.and()
|
||||
.requestCache((c) -> c.requestCache(this.requestCache));
|
||||
// @formatter:on
|
||||
|
||||
+6
-39
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,7 +23,6 @@ import io.mockk.verify
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
@@ -32,19 +31,19 @@ import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
|
||||
import org.springframework.stereotype.Controller
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.post
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
|
||||
|
||||
/**
|
||||
* Tests for [FormLoginDsl]
|
||||
@@ -103,38 +102,6 @@ class FormLoginDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when formLogin disabled does not provide login page`() {
|
||||
this.spring.register(DisabledConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/login")
|
||||
.andExpect {
|
||||
status { isNotFound() }
|
||||
}
|
||||
|
||||
this.mockMvc.post("/login") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isNotFound() }
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
open class DisabledConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http.formLogin()
|
||||
http {
|
||||
formLogin {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secure then redirects to default login page`() {
|
||||
this.spring.register(AllSecuredConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
-189
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.verify
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.BeanCreationException
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.ProviderManager
|
||||
import org.springframework.security.authentication.TestingAuthenticationProvider
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.saml2.core.Saml2X509Credential
|
||||
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponse
|
||||
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponseResolver
|
||||
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository
|
||||
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import java.security.cert.Certificate
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.util.Base64
|
||||
|
||||
/**
|
||||
* Tests for [Saml2Dsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class Saml2MetadataDslTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `saml2Metadat when no relying party registration repository then exception`() {
|
||||
Assertions.assertThatThrownBy { this.spring.register(Saml2MetadataNoRelyingPartyRegistrationRepoConfig::class.java).autowire() }
|
||||
.isInstanceOf(BeanCreationException::class.java)
|
||||
.hasMessageContaining("relyingPartyRegistrationRepository cannot be null")
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
open class Saml2MetadataNoRelyingPartyRegistrationRepoConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
saml2Metadata { }
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `metadata endpoint when saml2Metadata configured then metadata returned`() {
|
||||
this.spring.register(Saml2MetadataConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/saml2/metadata")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
open class Saml2MetadataConfig {
|
||||
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
saml2Metadata { }
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun registrations(): RelyingPartyRegistrationRepository {
|
||||
return InMemoryRelyingPartyRegistrationRepository(TestRelyingPartyRegistrations.full().build())
|
||||
}
|
||||
|
||||
private fun <T : Certificate> loadCert(location: String): T {
|
||||
ClassPathResource(location).inputStream.use { inputStream ->
|
||||
val certFactory = CertificateFactory.getInstance("X.509")
|
||||
return certFactory.generateCertificate(inputStream) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `metadata endpoint when url customized then used`() {
|
||||
this.spring.register(Saml2LoginCustomEndpointConfig::class.java).autowire()
|
||||
this.mockMvc.get("/saml/metadata")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
open class Saml2LoginCustomEndpointConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
saml2Metadata {
|
||||
metadataUrl = "/saml/metadata"
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun relyingPartyRegistrationRepository(): RelyingPartyRegistrationRepository? {
|
||||
return InMemoryRelyingPartyRegistrationRepository(TestRelyingPartyRegistrations.full().build())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `metadata endpoint when resolver customized then used`() {
|
||||
this.spring.register(Saml2LoginCustomMetadataResolverConfig::class.java).autowire()
|
||||
val mocked = this.spring.context.getBean(Saml2MetadataResponseResolver::class.java)
|
||||
every {
|
||||
mocked.resolve(any())
|
||||
} returns Saml2MetadataResponse("metadata", "file")
|
||||
this.mockMvc.get("/saml2/metadata")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
verify(exactly = 1) { mocked.resolve(any()) }
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
open class Saml2LoginCustomMetadataResolverConfig {
|
||||
|
||||
private val metadataResponseResolver: Saml2MetadataResponseResolver = mockk()
|
||||
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
saml2Metadata {}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun metadataResponseResolver(): Saml2MetadataResponseResolver? {
|
||||
return this.metadataResponseResolver
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun relyingPartyRegistrationRepository(): RelyingPartyRegistrationRepository? {
|
||||
return InMemoryRelyingPartyRegistrationRepository(TestRelyingPartyRegistrations.full().build())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
|
||||
http://www.springframework.org/schema/security org/springframework/security/config/spring-security-6.1.xsd">
|
||||
http://www.springframework.org/schema/security org/springframework/security/config/spring-security-6.0.xsd">
|
||||
|
||||
<tx:annotation-driven />
|
||||
|
||||
|
||||
+26
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,6 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
/**
|
||||
* Base root object for use in Spring Security expression evaluations.
|
||||
@@ -87,11 +86,7 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
* @since 5.8
|
||||
*/
|
||||
public SecurityExpressionRoot(Supplier<Authentication> authentication) {
|
||||
this.authentication = SingletonSupplier.of(() -> {
|
||||
Authentication value = authentication.get();
|
||||
Assert.notNull(value, "Authentication object cannot be null");
|
||||
return value;
|
||||
});
|
||||
this.authentication = new AuthenticationSupplier(authentication);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,7 +153,7 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
@Override
|
||||
public final boolean isFullyAuthenticated() {
|
||||
Authentication authentication = getAuthentication();
|
||||
return this.trustResolver.isFullyAuthenticated(authentication);
|
||||
return !this.trustResolver.isAnonymous(authentication) && !this.trustResolver.isRememberMe(authentication);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,4 +236,27 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
return defaultRolePrefix + role;
|
||||
}
|
||||
|
||||
private static final class AuthenticationSupplier implements Supplier<Authentication> {
|
||||
|
||||
private Authentication value;
|
||||
|
||||
private final Supplier<Authentication> delegate;
|
||||
|
||||
private AuthenticationSupplier(Supplier<Authentication> delegate) {
|
||||
Assert.notNull(delegate, "delegate cannot be null");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication get() {
|
||||
if (this.value == null) {
|
||||
Authentication authentication = this.delegate.get();
|
||||
Assert.notNull(authentication, "Authentication object cannot be null");
|
||||
this.value = authentication;
|
||||
}
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-17
@@ -53,21 +53,4 @@ public interface AuthenticationTrustResolver {
|
||||
*/
|
||||
boolean isRememberMe(Authentication authentication);
|
||||
|
||||
/**
|
||||
* Indicates whether the passed <code>Authentication</code> token represents a fully
|
||||
* authenticated user (that is, neither anonymous or remember-me). This is a
|
||||
* composition of <code>isAnonymous</code> and <code>isRememberMe</code>
|
||||
* implementation
|
||||
* <p>
|
||||
* @param authentication to test (may be <code>null</code> in which case the method
|
||||
* will always return <code>false</code>)
|
||||
* @return <code>true</code> the passed authentication token represented an anonymous
|
||||
* principal and is authenticated using a remember-me token, <code>false</code>
|
||||
* otherwise
|
||||
* @since 6.1
|
||||
*/
|
||||
default boolean isFullyAuthenticated(Authentication authentication) {
|
||||
return !isAnonymous(authentication) && !isRememberMe(authentication);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationConvention;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
@@ -36,7 +35,7 @@ public final class ObservationAuthenticationManager implements AuthenticationMan
|
||||
|
||||
private final AuthenticationManager delegate;
|
||||
|
||||
private ObservationConvention<AuthenticationObservationContext> convention = new AuthenticationObservationConvention();
|
||||
private final AuthenticationObservationConvention convention = new AuthenticationObservationConvention();
|
||||
|
||||
public ObservationAuthenticationManager(ObservationRegistry registry, AuthenticationManager delegate) {
|
||||
Assert.notNull(registry, "observationRegistry cannot be null");
|
||||
@@ -57,15 +56,4 @@ public final class ObservationAuthenticationManager implements AuthenticationMan
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the provided convention for reporting observation data
|
||||
* @param convention The provided convention
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public void setObservationConvention(ObservationConvention<AuthenticationObservationContext> convention) {
|
||||
Assert.notNull(convention, "The observation convention cannot be null");
|
||||
this.convention = convention;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,14 +17,12 @@
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationConvention;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link ReactiveAuthenticationManager} that observes the authentication
|
||||
@@ -38,7 +36,7 @@ public class ObservationReactiveAuthenticationManager implements ReactiveAuthent
|
||||
|
||||
private final ReactiveAuthenticationManager delegate;
|
||||
|
||||
private ObservationConvention<AuthenticationObservationContext> convention = new AuthenticationObservationConvention();
|
||||
private final AuthenticationObservationConvention convention = new AuthenticationObservationConvention();
|
||||
|
||||
public ObservationReactiveAuthenticationManager(ObservationRegistry registry,
|
||||
ReactiveAuthenticationManager delegate) {
|
||||
@@ -64,15 +62,4 @@ public class ObservationReactiveAuthenticationManager implements ReactiveAuthent
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the provided convention for reporting observation data
|
||||
* @param convention The provided convention
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public void setObservationConvention(ObservationConvention<AuthenticationObservationContext> convention) {
|
||||
Assert.notNull(convention, "The observation convention cannot be null");
|
||||
this.convention = convention;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -71,6 +71,7 @@ public class SecurityContextLoginModule implements LoginModule {
|
||||
* <code>Authentication</code>.
|
||||
* @return true if this method succeeded, or false if this <code>LoginModule</code>
|
||||
* should be ignored.
|
||||
* @exception LoginException if the abort fails
|
||||
*/
|
||||
@Override
|
||||
public boolean abort() {
|
||||
@@ -86,6 +87,7 @@ public class SecurityContextLoginModule implements LoginModule {
|
||||
* <code>Authentication</code> to the <code>Subject</code>'s principals.
|
||||
* @return true if this method succeeded, or false if this <code>LoginModule</code>
|
||||
* should be ignored.
|
||||
* @exception LoginException if the commit fails
|
||||
*/
|
||||
@Override
|
||||
public boolean commit() {
|
||||
@@ -159,6 +161,7 @@ public class SecurityContextLoginModule implements LoginModule {
|
||||
* Log out the <code>Subject</code>.
|
||||
* @return true if this method succeeded, or false if this <code>LoginModule</code>
|
||||
* should be ignored.
|
||||
* @exception LoginException if the logout fails
|
||||
*/
|
||||
@Override
|
||||
public boolean logout() {
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@ public final class AuthenticatedAuthorizationManager<T> implements Authorization
|
||||
|
||||
@Override
|
||||
boolean isGranted(Authentication authentication) {
|
||||
return authentication != null && this.trustResolver.isFullyAuthenticated(authentication);
|
||||
return super.isGranted(authentication) && !this.trustResolver.isRememberMe(authentication);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationManager} that determines if the current user is authorized by
|
||||
* evaluating if the {@link Authentication} contains any of the specified authorities.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 6.1
|
||||
*/
|
||||
public final class AuthoritiesAuthorizationManager implements AuthorizationManager<Collection<String>> {
|
||||
|
||||
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
|
||||
|
||||
/**
|
||||
* Sets the {@link RoleHierarchy} to be used. Default is {@link NullRoleHierarchy}.
|
||||
* Cannot be null.
|
||||
* @param roleHierarchy the {@link RoleHierarchy} to use
|
||||
*/
|
||||
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
|
||||
Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current user is authorized by evaluating if the
|
||||
* {@link Authentication} contains any of specified authorities.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param authorities the collection of authority strings to check
|
||||
* @return an {@link AuthorityAuthorizationDecision}
|
||||
*/
|
||||
@Override
|
||||
public AuthorityAuthorizationDecision check(Supplier<Authentication> authentication,
|
||||
Collection<String> authorities) {
|
||||
boolean granted = isGranted(authentication.get(), authorities);
|
||||
return new AuthorityAuthorizationDecision(granted, AuthorityUtils.createAuthorityList(authorities));
|
||||
}
|
||||
|
||||
private boolean isGranted(Authentication authentication, Collection<String> authorities) {
|
||||
return authentication != null && isAuthorized(authentication, authorities);
|
||||
}
|
||||
|
||||
private boolean isAuthorized(Authentication authentication, Collection<String> authorities) {
|
||||
for (GrantedAuthority grantedAuthority : getGrantedAuthorities(authentication)) {
|
||||
if (authorities.contains(grantedAuthority.getAuthority())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Collection<? extends GrantedAuthority> getGrantedAuthorities(Authentication authentication) {
|
||||
return this.roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user