1
0
mirror of synced 2026-07-14 07:05:11 +00:00

Compare commits

..

90 Commits

Author SHA1 Message Date
github-actions[bot] d6eeafb10c Release 5.7.8 2023-04-17 15:21:42 +00:00
Marcus Da Coregio 2d52fb8e4b Clear Repository on Logout 2023-04-17 06:47:57 -03:00
Marcus Da Coregio 37d8846652 Update org.springframework.data to 2021.2.11
Closes gh-13019
2023-04-14 13:57:28 -03:00
Marcus Da Coregio 74b8c6715b Update org.springframework to 5.3.27
Closes gh-13018
2023-04-14 10:41:45 -03:00
Marcus Da Coregio 8c9275067e Update org.eclipse.jetty to 9.4.51.v20230217
Closes gh-13017
2023-04-14 10:41:41 -03:00
Marcus Da Coregio 4b8bfee7c5 Update blockhound to 1.0.8.RELEASE
Closes gh-13016
2023-04-14 10:41:37 -03:00
Marcus Da Coregio b727f24c95 Update io.projectreactor to 2020.0.31
Closes gh-13014
2023-04-14 10:41:31 -03:00
Marcus Da Coregio d55c8aac4f Update logback-classic to 1.2.12
Closes gh-13013
2023-04-14 10:41:27 -03:00
Nick Meverden c4e9fb885d Delay JWSVerificationKeySelector Construction
Updating the NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder processor to execute the ConfigurableJWTProcessor customizations before holding a reference to the JWSKeySelector.

Closes gh-12960
2023-04-12 12:45:00 -06:00
Christian Marck 442faccb5f Avoid NPE in FilterInvocation
Handle unknown headers in dummy request wrapper.

Closes gh-12998
2023-04-11 17:01:59 -06:00
Marcus Da Coregio e25117856e Add static imports to code snippets
Closes gh-6597
2023-04-11 09:56:19 -03:00
Yuanhang Guo c69df9fba0 Fix javadoc typo in ReactiveAuthorizationManager
Closes gh-12978
2023-04-10 11:24:49 -05:00
Josh Cummings 39cee36065 Use SingletonSupplier
Issue gh-9991
2023-04-04 13:25:31 -06:00
Tatiana Slednikova a106188add Add nameIdFormat processing to OpenSamlAuthenticationRequestResolver
Closes gh-12825
2023-03-27 16:33:11 -06:00
Martin Tarjányi 5eefe9dcff Fix typo in SessionManagementConfigurer javadoc 2023-03-22 10:07:44 -03:00
Siva Kumar Edupuganti 98321b769a Fixed Broken Support Link
Closes gh-12759
2023-03-20 16:59:04 -06:00
twosom 3d7e22a4e9 Add test to SimpleUrlAuthenticationSuccessHandlerTests 2023-03-20 16:20:30 -06:00
Marcus Da Coregio 84cca81edf Use HttpSessionSecurityContextRepository by default in SwitchUserFilter
Closes gh-12834
2023-03-07 13:27:18 -03:00
bist 094bf1b527 Validate hasRole Input
There are no check for role prefix in AuthorizeHttpRequestsConfigurer#XXXrole
methods. This PR adds check for the same. Now the configuration
will fail if role/s start with prefix for hasRole and hasAnyRole methods.

Closes #12581
2023-03-03 15:00:34 -07:00
Josh Cummings 66665344c5 Formatting
Issue gh-12664
2023-03-01 11:23:45 -07:00
stnor 6c7703789a Ignore SPSSODescriptor elements
Closes gh-12664
2023-03-01 11:23:45 -07:00
Steve Riesenberg fabf7f649c Fix path of copied schema files
Issue gh-12804
2023-03-01 11:49:36 -06:00
Steve Riesenberg 7b88ab289d Add nohttp exclusion
Issue gh-12804
2023-02-28 16:52:19 -06:00
Steve Riesenberg 26566af431 Copy spring-security-oauth schemas on deploy
Closes gh-12804
2023-02-28 16:16:08 -06:00
Steve Riesenberg 5257e36ffc Update SaganApi to work with Contentful backend
Also fixed an issue with incorrect referenceDocUrl for Antora
with SNAPSHOT versions.

Closes gh-12575
2023-02-28 14:09:51 -06:00
Josh Cummings 0421e25cba Document Common SAML URI Endpoints
Issue gh-12764
2023-02-28 12:45:48 -07:00
Josh Cummings 1c885cf3a3 Document Federation Usecase
Closes gh-12764
2023-02-28 12:35:04 -07:00
Marcus Da Coregio 1c3ce1e401 Fix entity-id ignored in RelyingPartyRegistration XML config
Closes gh-11898
2023-02-23 15:16:40 -03:00
github-actions[bot] b851a8bf6d Next development version 2023-02-21 15:20:58 +00:00
github-actions[bot] faadadf71a Release 5.7.7 2023-02-21 14:41:42 +00:00
Josh Cummings 2fcf48a11b Update org.springframework.data to 2021.2.8
Closes gh-12738
2023-02-17 15:53:49 -07:00
Josh Cummings 0398d86f39 Update org.springframework to 5.3.25
Closes gh-12737
2023-02-17 15:53:40 -07:00
Josh Cummings c9112dfaab Update hibernate-entitymanager to 5.6.15.Final
Closes gh-12736
2023-02-17 15:53:32 -07:00
Josh Cummings 4156766fe0 Update org.aspectj to 1.9.19
Closes gh-12735
2023-02-17 15:53:24 -07:00
Josh Cummings f125785328 Update io.spring.nohttp to 0.0.11
Closes gh-12734
2023-02-17 15:53:16 -07:00
Josh Cummings 4643c0d999 Update blockhound to 1.0.7.RELEASE
Closes gh-12733
2023-02-17 15:53:08 -07:00
Josh Cummings d2d82b5e94 Update io.projectreactor to 2020.0.28
Closes gh-12732
2023-02-17 15:52:54 -07:00
Josh Cummings d4d03ea146 Update jackson-bom to 2.13.5
Closes gh-12731
2023-02-17 15:52:32 -07:00
Josh Cummings 2db4430dcd Preserve OpenSamlAssertingPartyDetails Instance
Closes gh-12667
2023-02-17 10:02:17 -07:00
Leonid Rozenblyum 000b4bc495 Fix NPE in HttpSecurity#addFilterBefore, HttpSecurity#addFilterAfter
Before the fix, these methods would throw a NPE in case when the filter class passed as the second parameter, is not registered yet.

In particular, this exception can occur when mixing standard and custom DSL to register filters.

The fix doesn't change the situation that standard DSL for registration of filters cannot refer to filters that are registered via custom DSL even though those calls were done earlier.

It just provides more user-friendly error handling for this and most likely other scenarios of calls of HttpSecurity#addFilterBefore, HttpSecurity#addFilterAfter.

The error handling is implemented similarly to HttpSecurity#addFilter.

Closes gh-12637
2023-02-16 14:54:44 -07:00
jongwooo aad3e61f4d chore: Use cache in continuous-integration-workflow.yml
Signed-off-by: jongwooo <jongwooo.han@gmail.com>
2023-02-01 14:26:25 -07:00
Dan Allen 51d5fb9c03 upgrade the Gradle Antora Plugin to 1.0.0 2023-01-30 16:04:40 -06:00
Rob Winch 7db357d36a Use io.spring.antora.generate-antora-yml 2023-01-17 17:05:55 -06:00
Dan Allen f5bc6ce665 fix unclosed block in docs 2023-01-17 15:02:30 -06:00
Dan Allen 4cbb057b97 enable fetch option in Antora unless Gradle is running in offline mode 2023-01-17 14:42:54 -03:00
Marcus Da Coregio c0f7cecc6d Merge branch '5.6.x' into 5.7.x 2023-01-17 09:46:41 -03:00
Dan Allen 22ffa833ca upgrade Antora plugin and configure playbook provider to support local build 2023-01-17 09:46:24 -03:00
Josh Cummings f41b77a4db Fix Diagram to Say SecurityContextHolderFilter
Closes gh-11800
2023-01-11 12:47:07 -07:00
Josh Cummings 2028507bf8 Fix Typo in Sample
Closes gh-11095
2023-01-10 10:38:28 -07:00
Marcus Da Coregio ffdb397830 Save the SecurityContext when switching user
Closes gh-12504
2023-01-10 09:27:56 -03:00
Jon Kjennbakken 225dc593a8 Polish NimbusJwtDecoderTests
- Add missing mock

Closes gh-12238
2023-01-06 12:53:36 -07:00
Josh Cummings 3cfaf0d11d Avoid LinkedMultiValueMap in Serializable Object
Closes gh-11785
2022-12-23 15:54:00 -07:00
Eleftheria Stein-Kousathana fbfa13bd47 Fix OAuth 2.0 testing docs 2022-12-19 16:52:25 -03:00
Marcus Da Coregio 0c6b427132 Merge branch '5.6.x' into 5.7.x 2022-12-19 15:03:50 -03:00
github-actions[bot] 0f7d17bae6 Next development version 2022-12-19 15:59:53 +00:00
github-actions[bot] c11248b589 Next development version 2022-12-19 15:57:16 +00:00
github-actions[bot] 972075677f Release 5.6.10 2022-12-19 15:23:12 +00:00
github-actions[bot] 11614edcfe Release 5.7.6 2022-12-19 15:22:32 +00:00
Steve Riesenberg 2461d00f4d Merge branch '5.6.x' into 5.7.x
Closes gh-12407
2022-12-15 15:52:02 -06:00
Dayan Kodippily eec6729125 Fix DefaultLdapAuthoritiesPopulator NPE
Closes gh-12090
2022-12-15 15:51:07 -06:00
Marcus Da Coregio fc9c2513d8 Merge branch '5.6.x' into 5.7.x
Closes gh-dry-run
2022-12-15 15:23:13 -03:00
Marcus Da Coregio 1f3c4707f3 Update org.springframework.data to 2021.2.6
Closes gh-12399
2022-12-15 15:11:54 -03:00
Marcus Da Coregio 579fc565ae Update org.springframework to 5.3.24
Closes gh-12398
2022-12-15 15:11:49 -03:00
Marcus Da Coregio 5cf23585c0 Update hibernate-entitymanager to 5.6.14.Final
Closes gh-12397
2022-12-15 15:11:41 -03:00
Marcus Da Coregio 50d793eab2 Update org.eclipse.jetty to 9.4.50.v20221201
Closes gh-12396
2022-12-15 15:11:36 -03:00
Marcus Da Coregio c715df687a Update httpclient to 4.5.14
Closes gh-12395
2022-12-15 15:11:30 -03:00
Marcus Da Coregio 4ddecdbe36 Update io.projectreactor to 2020.0.26
Closes gh-12393
2022-12-15 15:11:22 -03:00
Marcus Da Coregio 94c8830f76 Update jackson-bom to 2.13.4.20221013
Closes gh-12391
2022-12-15 15:11:12 -03:00
Marcus Da Coregio 885f1d3165 Update org.springframework.data to 2021.1.10
Closes gh-12390
2022-12-15 14:59:27 -03:00
Marcus Da Coregio e414d2bd5c Update org.springframework to 5.3.24
Closes gh-12389
2022-12-15 14:59:27 -03:00
Marcus Da Coregio dbcc3130ee Update hibernate-entitymanager to 5.6.14.Final
Closes gh-12388
2022-12-15 14:59:27 -03:00
Marcus Da Coregio ac9c398fea Update org.eclipse.jetty to 9.4.50.v20221201
Closes gh-12387
2022-12-15 14:59:26 -03:00
Marcus Da Coregio 7c428fb75e Update httpclient to 4.5.14
Closes gh-12386
2022-12-15 14:59:26 -03:00
Marcus Da Coregio aa1934ee95 Update io.projectreactor to 2020.0.26
Closes gh-12384
2022-12-15 14:59:26 -03:00
Marcus Da Coregio 58e8fe837f Update jackson-bom to 2.13.4.20221013
Closes gh-12381
2022-12-15 14:58:07 -03:00
Marcus Da Coregio fc25b87967 Merge branch '5.6.x' into 5.7.x 2022-12-05 14:40:38 -08:00
Mitja Kotnik f39f215140 Replace javadoc with SecurityFilterChain bean definition 2022-12-05 14:40:05 -08:00
Sellami 626e53d121 Fix: Replace tenantRepository with tenants 2022-12-05 14:31:24 -08:00
Guillaume Husta a5464ed819 Fix typo in DefaultLoginPageConfigurer Javadoc
'isLogoutRequest' seems to have nothing to do here.
2022-12-05 14:31:15 -08:00
Josh Cummings 667cab6cda Merge branch '5.6.x' into 5.7.x
Closes gh-12323
2022-11-30 14:38:16 -07:00
이경욱 52c7141aac Save Request Before Response Is Committed
Specifically important for cookie-based authorization request
repositories.

Closes gh-11602
2022-11-30 14:33:08 -07:00
Josh Cummings e23c1cf7a7 Merge branch '5.6.x' into 5.7.x 2022-11-30 14:18:12 -07:00
Josh Cummings 14a48ea939 Fix formatting
Issue gh-12143
2022-11-29 20:15:13 -07:00
Junsung Cho 709de43e89 Fix typo in JavaDoc
Closes gh-12143
2022-11-29 20:15:12 -07:00
Marcus Da Coregio c2e86ad067 Merge branch '5.6.x' into 5.7.x
Closes gh-12297
2022-11-25 09:22:10 -03:00
Kirk Lin 9c6d90490d ci: fix GitHub Actions Deprecating save-state and set-output commands
Closes gh-12032
2022-11-25 09:05:28 -03:00
Marcus Da Coregio 9b3f834bff Merge branch '5.6.x' into 5.7.x
Closes gh-12285
2022-11-24 08:47:46 -03:00
Marcus Da Coregio 70bfc39418 Fix AuthorizationFilter diagram in docs
Closes gh-12274
2022-11-24 08:46:16 -03:00
Steve Riesenberg 621889fa18 Merge branch '5.6.x' into 5.7.x 2022-11-23 17:12:30 -06:00
Dan Allen fe252f5057 sync docs build; upgrade Antora and Antora Collector to latest alpha 2022-11-21 17:26:51 -07:00
782 changed files with 4767 additions and 38573 deletions
@@ -31,15 +31,15 @@ jobs:
runjobs: ${{ steps.continue.outputs.runjobs }}
project_version: ${{ steps.continue.outputs.project_version }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- id: continue
name: Determine if should continue
run: |
# Run jobs if in upstream repository
echo "::set-output name=runjobs::true"
echo "runjobs=true" >>$GITHUB_OUTPUT
# Extract version from gradle.properties
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
echo "::set-output name=project_version::$version"
echo "project_version=$version" >>$GITHUB_OUTPUT
build_jdk_11:
name: Build JDK 11
needs: [prerequisites]
@@ -49,12 +49,13 @@ jobs:
runs-on: ${{ matrix.os }}
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v2
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'adopt'
cache: 'gradle'
- name: Set up Gradle
uses: gradle/gradle-build-action@v2
- name: Set up gradle user name
@@ -71,7 +72,7 @@ jobs:
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
@@ -89,7 +90,7 @@ jobs:
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
@@ -113,7 +114,7 @@ jobs:
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
@@ -130,7 +131,7 @@ jobs:
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
@@ -154,7 +155,7 @@ jobs:
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
@@ -175,7 +176,7 @@ jobs:
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
@@ -205,7 +206,7 @@ jobs:
TOKEN: ${{ github.token }}
VERSION: ${{ needs.prerequisites.outputs.project_version }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Set up gradle
@@ -286,7 +287,7 @@ jobs:
TOKEN: ${{ github.token }}
VERSION: ${{ needs.prerequisites.outputs.project_version }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
@@ -23,7 +23,7 @@ jobs:
steps:
- id: checkout-source
name: Checkout Source Code
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Set up gradle
@@ -38,7 +38,7 @@ jobs:
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew gitHubCheckNextVersionDueToday
echo "::set-output name=is_due_today::$(cat build/github/milestones/is-due-today)"
echo "is_due_today=$(cat build/github/milestones/is-due-today)" >>$GITHUB_OUTPUT
- id: check-open-issues
name: Check for open issues
if: steps.check-release-due.outputs.is_due_today == 'true'
@@ -47,7 +47,7 @@ jobs:
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew gitHubCheckMilestoneHasNoOpenIssues
echo "::set-output name=is_open_issues::$(cat build/github/milestones/is-open-issues)"
echo "is_open_issues=$(cat build/github/milestones/is-open-issues)" >>$GITHUB_OUTPUT
- id: validate-release-state
name: Validate State of Release
if: steps.check-release-due.outputs.is_due_today == 'true' && steps.check-open-issues.outputs.is_open_issues == 'true'
+1 -1
View File
@@ -57,7 +57,7 @@ See also the https://github.com/spring-projects/spring-framework/wiki/Gradle-bui
== Getting Support
Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow].
https://spring.io/services[Commercial support] is available too.
https://spring.io/support[Commercial support] is available too.
== Contributing
https://help.github.com/articles/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/main/CONTRIBUTING.adoc[contributor guidelines] for details.
@@ -27,9 +27,7 @@ import org.springframework.security.acls.model.SidRetrievalStrategy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.Assert;
/**
@@ -48,9 +46,6 @@ import org.springframework.util.Assert;
*/
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private final GrantedAuthority gaGeneralChanges;
private final GrantedAuthority gaModifyAuditing;
@@ -86,12 +81,12 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
@Override
public void securityCheck(Acl acl, int changeType) {
SecurityContext context = this.securityContextHolderStrategy.getContext();
if ((context == null) || (context.getAuthentication() == null)
|| !context.getAuthentication().isAuthenticated()) {
if ((SecurityContextHolder.getContext() == null)
|| (SecurityContextHolder.getContext().getAuthentication() == null)
|| !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
throw new AccessDeniedException("Authenticated principal required to operate with ACLs");
}
Authentication authentication = context.getAuthentication();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// Check if authorized by virtue of ACL ownership
Sid currentUser = createCurrentUser(authentication);
if (currentUser.equals(acl.getOwner())
@@ -151,15 +146,4 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
/**
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
*
* @since 5.8
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
}
@@ -40,7 +40,6 @@ import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
@@ -65,9 +64,6 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
private static final String DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID = "insert into acl_class (class, class_id_type) values (?, ?)";
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private boolean foreignKeysInDatabase = true;
private final AclCache aclCache;
@@ -119,7 +115,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
// Need to retrieve the current principal, in order to know who "owns" this ACL
// (can be changed later on)
Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
PrincipalSid sid = new PrincipalSid(auth);
// Create the acl_object_identity row
@@ -477,15 +473,4 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
}
}
/**
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
*
* @since 5.8
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
}
@@ -34,7 +34,7 @@ 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.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* @author Luke Taylor
@@ -68,7 +68,7 @@ public class AclPermissionCacheOptimizerTests {
pco.setObjectIdentityRetrievalStrategy(oids);
pco.setSidRetrievalStrategy(sids);
pco.cachePermissionsFor(mock(Authentication.class), Collections.emptyList());
verifyNoMoreInteractions(service, sids, oids);
verifyZeroInteractions(service, sids, oids);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,13 +29,9 @@ import org.springframework.security.acls.model.Acl;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
/**
* @author Rob Winch
@@ -44,14 +40,9 @@ import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
public class AclAuthorizationStrategyImplTests {
SecurityContext context;
@Mock
Acl acl;
@Mock
SecurityContextHolderStrategy securityContextHolderStrategy;
GrantedAuthority authority;
AclAuthorizationStrategyImpl strategy;
@@ -62,8 +53,7 @@ public class AclAuthorizationStrategyImplTests {
TestingAuthenticationToken authentication = new TestingAuthenticationToken("foo", "bar",
Arrays.asList(this.authority));
authentication.setAuthenticated(true);
this.context = new SecurityContextImpl(authentication);
SecurityContextHolder.setContext(this.context);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
@AfterEach
@@ -86,16 +76,6 @@ public class AclAuthorizationStrategyImplTests {
this.strategy.securityCheck(this.acl, AclAuthorizationStrategy.CHANGE_GENERAL);
}
@Test
public void securityCheckWhenCustomSecurityContextHolderStrategyThenUses() {
given(this.securityContextHolderStrategy.getContext()).willReturn(this.context);
given(this.acl.getOwner()).willReturn(new GrantedAuthoritySid("ROLE_AUTH"));
this.strategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_SYSTEM_ADMIN"));
this.strategy.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
this.strategy.securityCheck(this.acl, AclAuthorizationStrategy.CHANGE_GENERAL);
verify(this.securityContextHolderStrategy).getContext();
}
@SuppressWarnings("serial")
class CustomAuthority implements GrantedAuthority {
@@ -48,10 +48,7 @@ import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.sid.CustomSid;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.transaction.AfterTransaction;
@@ -62,9 +59,7 @@ 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.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/**
* Integration tests the ACL system using an in-memory database.
@@ -355,19 +350,6 @@ public class JdbcMutableAclServiceTests {
assertThat(this.jdbcMutableAclService.readAclById(new ObjectIdentityImpl(TARGET_CLASS, 101L))).isNotNull();
}
@Test
@Transactional
public void createAclWhenCustomSecurityContextHolderStrategyThenUses() {
SecurityContextHolderStrategy securityContextHolderStrategy = mock(SecurityContextHolderStrategy.class);
SecurityContext context = new SecurityContextImpl(this.auth);
given(securityContextHolderStrategy.getContext()).willReturn(context);
JdbcMutableAclService service = new JdbcMutableAclService(this.dataSource, this.lookupStrategy, this.aclCache);
service.setSecurityContextHolderStrategy(securityContextHolderStrategy);
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS, 101);
service.createAcl(oid);
verify(securityContextHolderStrategy).getContext();
}
/**
* SEC-655
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,9 +37,7 @@ import org.springframework.security.access.prepost.PreFilter;
* @author Mike Wiesner
* @author Luke Taylor
* @since 3.1
* @deprecated Use aspects in {@link org.springframework.security.authorization.method.aspectj} instead
*/
@Deprecated
public aspect AnnotationSecurityAspect implements InitializingBean {
/**
@@ -1,61 +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.method.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.prepost.PostAuthorize;
/**
* Abstract AspectJ aspect for adapting a {@link MethodInvocation}
*
* @author Josh Cummings
* @since 5.8
*/
abstract aspect AbstractMethodInterceptorAspect {
protected abstract pointcut executionOfAnnotatedMethod();
private MethodInterceptor securityInterceptor;
Object around(): executionOfAnnotatedMethod() {
if (this.securityInterceptor == null) {
return proceed();
}
MethodInvocation invocation = new JoinPointMethodInvocation(thisJoinPoint, () -> proceed());
try {
return this.securityInterceptor.invoke(invocation);
} catch (Throwable t) {
throwUnchecked(t);
throw new IllegalStateException("Code unexpectedly reached", t);
}
}
public void setSecurityInterceptor(MethodInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
private static void throwUnchecked(Throwable ex) {
AbstractMethodInterceptorAspect.<RuntimeException>throwAny(ex);
}
@SuppressWarnings("unchecked")
private static <E extends Throwable> void throwAny(Throwable ex) throws E {
throw (E) ex;
}
}
@@ -1,98 +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.method.aspectj;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.util.Assert;
class JoinPointMethodInvocation implements MethodInvocation {
private final JoinPoint jp;
private final Method method;
private final Object target;
private final Supplier<Object> proceed;
JoinPointMethodInvocation(JoinPoint jp, Supplier<Object> proceed) {
this.jp = jp;
if (jp.getTarget() != null) {
this.target = jp.getTarget();
}
else {
// SEC-1295: target may be null if an ITD is in use
this.target = jp.getSignature().getDeclaringType();
}
String targetMethodName = jp.getStaticPart().getSignature().getName();
Class<?>[] types = ((CodeSignature) jp.getStaticPart().getSignature()).getParameterTypes();
Class<?> declaringType = jp.getStaticPart().getSignature().getDeclaringType();
this.method = findMethod(targetMethodName, declaringType, types);
Assert.notNull(this.method, () -> "Could not obtain target method from JoinPoint: '" + jp + "'");
this.proceed = proceed;
}
private Method findMethod(String name, Class<?> declaringType, Class<?>[] params) {
Method method = null;
try {
method = declaringType.getMethod(name, params);
}
catch (NoSuchMethodException ignored) {
}
if (method == null) {
try {
method = declaringType.getDeclaredMethod(name, params);
}
catch (NoSuchMethodException ignored) {
}
}
return method;
}
@Override
public Method getMethod() {
return this.method;
}
@Override
public Object[] getArguments() {
return this.jp.getArgs();
}
@Override
public AccessibleObject getStaticPart() {
return this.method;
}
@Override
public Object getThis() {
return this.target;
}
@Override
public Object proceed() throws Throwable {
return this.proceed.get();
}
}
@@ -1,44 +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.method.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.prepost.PostAuthorize;
/**
* Concrete AspectJ aspect using Spring Security @PostAuthorize annotation.
*
* <p>
* When using this aspect, you <i>must</i> annotate the implementation class
* (and/or methods within that class), <i>not</i> the interface (if any) that
* the class implements. AspectJ follows Java's rule that annotations on
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
*
* @author Mike Wiesner
* @author Luke Taylor
* @author Josh Cummings
* @since 5.8
*/
public aspect PostAuthorizeAspect extends AbstractMethodInterceptorAspect {
/**
* Matches the execution of any method with a PostAuthorize annotation.
*/
protected pointcut executionOfAnnotatedMethod() : execution(* *(..)) && @annotation(PostAuthorize);
}
@@ -1,45 +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.method.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.prepost.PostFilter;
/**
* Concrete AspectJ aspect using Spring Security @PostFilter annotation.
*
* <p>
* When using this aspect, you <i>must</i> annotate the implementation class
* (and/or methods within that class), <i>not</i> the interface (if any) that
* the class implements. AspectJ follows Java's rule that annotations on
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
*
* @author Mike Wiesner
* @author Luke Taylor
* @author Josh Cummings
* @since 5.8
*/
public aspect PostFilterAspect extends AbstractMethodInterceptorAspect {
/**
* Matches the execution of any method with a PostFilter annotation.
*/
protected pointcut executionOfAnnotatedMethod() : execution(* *(..)) && @annotation(PostFilter);
}
@@ -1,44 +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.method.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* Concrete AspectJ aspect using Spring Security @PreAuthorize annotation.
*
* <p>
* When using this aspect, you <i>must</i> annotate the implementation class
* (and/or methods within that class), <i>not</i> the interface (if any) that
* the class implements. AspectJ follows Java's rule that annotations on
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
*
* @author Mike Wiesner
* @author Luke Taylor
* @author Josh Cummings
* @since 5.8
*/
public aspect PreAuthorizeAspect extends AbstractMethodInterceptorAspect {
/**
* Matches the execution of any method with a PreAuthorize annotation.
*/
protected pointcut executionOfAnnotatedMethod() : execution(* *(..)) && @annotation(PreAuthorize);
}
@@ -1,45 +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.method.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.prepost.PreFilter;
/**
* Concrete AspectJ aspect using Spring Security @PreFilter annotation.
*
* <p>
* When using this aspect, you <i>must</i> annotate the implementation class
* (and/or methods within that class), <i>not</i> the interface (if any) that
* the class implements. AspectJ follows Java's rule that annotations on
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
*
* @author Mike Wiesner
* @author Luke Taylor
* @author Josh Cummings
* @since 5.8
*/
public aspect PreFilterAspect extends AbstractMethodInterceptorAspect {
/**
* Matches the execution of any method with a PreFilter annotation.
*/
protected pointcut executionOfAnnotatedMethod() : execution(* *(..)) && @annotation(PreFilter);
}
@@ -1,56 +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.method.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.annotation.Secured;
/**
* Concrete AspectJ aspect using Spring Security @Secured annotation.
*
* <p>
* When using this aspect, you <i>must</i> annotate the implementation class
* (and/or methods within that class), <i>not</i> the interface (if any) that
* the class implements. AspectJ follows Java's rule that annotations on
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
*
* @author Mike Wiesner
* @author Luke Taylor
* @author Josh Cummings
* @since 5.8
*/
public aspect SecuredAspect extends AbstractMethodInterceptorAspect {
/**
* Matches the execution of any public method in a type with the Secured
* annotation, or any subtype of a type with the Secured annotation.
*/
private pointcut executionOfAnyPublicMethodInAtSecuredType() :
execution(public * ((@Secured *)+).*(..)) && @this(Secured);
/**
* Matches the execution of any method with the Secured annotation.
*/
private pointcut executionOfSecuredMethod() :
execution(* *(..)) && @annotation(Secured);
protected pointcut executionOfAnnotatedMethod() :
executionOfAnyPublicMethodInAtSecuredType() ||
executionOfSecuredMethod();
}
@@ -1,160 +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.method.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
import org.springframework.security.core.context.SecurityContextHolder;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Luke Taylor
* @since 3.0.3
*/
public class PostAuthorizeAspectTests {
private TestingAuthenticationToken anne = new TestingAuthenticationToken("anne", "", "ROLE_A");
private MethodInterceptor interceptor;
private SecuredImpl secured = new SecuredImpl();
private SecuredImplSubclass securedSub = new SecuredImplSubclass();
private PrePostSecured prePostSecured = new PrePostSecured();
@BeforeEach
public final void setUp() {
MockitoAnnotations.initMocks(this);
this.interceptor = AuthorizationManagerAfterMethodInterceptor.postAuthorize();
PostAuthorizeAspect secAspect = PostAuthorizeAspect.aspectOf();
secAspect.setSecurityInterceptor(this.interceptor);
}
@AfterEach
public void clearContext() {
SecurityContextHolder.clearContext();
}
@Test
public void securedInterfaceMethodAllowsAllAccess() {
this.secured.securedMethod();
}
@Test
public void securedClassMethodDeniesUnauthenticatedAccess() {
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
.isThrownBy(() -> this.secured.securedClassMethod());
}
@Test
public void securedClassMethodAllowsAccessToRoleA() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
this.secured.securedClassMethod();
}
@Test
public void internalPrivateCallIsIntercepted() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.secured.publicCallsPrivate());
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.securedSub.publicCallsPrivate());
}
@Test
public void protectedMethodIsIntercepted() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.secured.protectedMethod());
}
@Test
public void overriddenProtectedMethodIsNotIntercepted() {
// AspectJ doesn't inherit annotations
this.securedSub.protectedMethod();
}
// SEC-1262
@Test
public void denyAllPreAuthorizeDeniesAccess() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.prePostSecured::denyAllMethod);
}
interface SecuredInterface {
@PostAuthorize("hasRole('X')")
void securedMethod();
}
static class SecuredImpl implements SecuredInterface {
// Not really secured because AspectJ doesn't inherit annotations from interfaces
@Override
public void securedMethod() {
}
@PostAuthorize("hasRole('A')")
void securedClassMethod() {
}
@PostAuthorize("hasRole('X')")
private void privateMethod() {
}
@PostAuthorize("hasRole('X')")
protected void protectedMethod() {
}
@PostAuthorize("hasRole('X')")
void publicCallsPrivate() {
privateMethod();
}
}
static class SecuredImplSubclass extends SecuredImpl {
@Override
protected void protectedMethod() {
}
@Override
public void publicCallsPrivate() {
super.publicCallsPrivate();
}
}
static class PrePostSecured {
@PostAuthorize("denyAll")
void denyAllMethod() {
}
}
}
@@ -1,66 +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.method.aspectj;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.aopalliance.intercept.MethodInterceptor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Luke Taylor
* @since 3.0.3
*/
public class PostFilterAspectTests {
private MethodInterceptor interceptor;
private PrePostSecured prePostSecured = new PrePostSecured();
@BeforeEach
public final void setUp() {
MockitoAnnotations.initMocks(this);
this.interceptor = new PostFilterAuthorizationMethodInterceptor();
PostFilterAspect secAspect = PostFilterAspect.aspectOf();
secAspect.setSecurityInterceptor(this.interceptor);
}
@Test
public void preFilterMethodWhenListThenFilters() {
List<String> objects = new ArrayList<>(Arrays.asList("apple", "banana", "aubergine", "orange"));
assertThat(this.prePostSecured.postFilterMethod(objects)).containsExactly("apple", "aubergine");
}
static class PrePostSecured {
@PostFilter("filterObject.startsWith('a')")
List<String> postFilterMethod(List<String> objects) {
return objects;
}
}
}
@@ -1,160 +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.method.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.core.context.SecurityContextHolder;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Luke Taylor
* @since 3.0.3
*/
public class PreAuthorizeAspectTests {
private TestingAuthenticationToken anne = new TestingAuthenticationToken("anne", "", "ROLE_A");
private MethodInterceptor interceptor;
private SecuredImpl secured = new SecuredImpl();
private SecuredImplSubclass securedSub = new SecuredImplSubclass();
private PrePostSecured prePostSecured = new PrePostSecured();
@BeforeEach
public final void setUp() {
MockitoAnnotations.initMocks(this);
this.interceptor = AuthorizationManagerBeforeMethodInterceptor.preAuthorize();
PreAuthorizeAspect secAspect = PreAuthorizeAspect.aspectOf();
secAspect.setSecurityInterceptor(this.interceptor);
}
@AfterEach
public void clearContext() {
SecurityContextHolder.clearContext();
}
@Test
public void securedInterfaceMethodAllowsAllAccess() {
this.secured.securedMethod();
}
@Test
public void securedClassMethodDeniesUnauthenticatedAccess() {
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
.isThrownBy(() -> this.secured.securedClassMethod());
}
@Test
public void securedClassMethodAllowsAccessToRoleA() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
this.secured.securedClassMethod();
}
@Test
public void internalPrivateCallIsIntercepted() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.secured.publicCallsPrivate());
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.securedSub.publicCallsPrivate());
}
@Test
public void protectedMethodIsIntercepted() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.secured.protectedMethod());
}
@Test
public void overriddenProtectedMethodIsNotIntercepted() {
// AspectJ doesn't inherit annotations
this.securedSub.protectedMethod();
}
// SEC-1262
@Test
public void denyAllPreAuthorizeDeniesAccess() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.prePostSecured::denyAllMethod);
}
interface SecuredInterface {
@PreAuthorize("hasRole('X')")
void securedMethod();
}
static class SecuredImpl implements SecuredInterface {
// Not really secured because AspectJ doesn't inherit annotations from interfaces
@Override
public void securedMethod() {
}
@PreAuthorize("hasRole('A')")
void securedClassMethod() {
}
@PreAuthorize("hasRole('X')")
private void privateMethod() {
}
@PreAuthorize("hasRole('X')")
protected void protectedMethod() {
}
@PreAuthorize("hasRole('X')")
void publicCallsPrivate() {
privateMethod();
}
}
static class SecuredImplSubclass extends SecuredImpl {
@Override
protected void protectedMethod() {
}
@Override
public void publicCallsPrivate() {
super.publicCallsPrivate();
}
}
static class PrePostSecured {
@PreAuthorize("denyAll")
void denyAllMethod() {
}
}
}
@@ -1,66 +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.method.aspectj;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.aopalliance.intercept.MethodInterceptor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Luke Taylor
* @since 3.0.3
*/
public class PreFilterAspectTests {
private MethodInterceptor interceptor;
private PrePostSecured prePostSecured = new PrePostSecured();
@BeforeEach
public final void setUp() {
MockitoAnnotations.initMocks(this);
this.interceptor = new PreFilterAuthorizationMethodInterceptor();
PreFilterAspect secAspect = PreFilterAspect.aspectOf();
secAspect.setSecurityInterceptor(this.interceptor);
}
@Test
public void preFilterMethodWhenListThenFilters() {
List<String> objects = new ArrayList<>(Arrays.asList("apple", "banana", "aubergine", "orange"));
assertThat(this.prePostSecured.preFilterMethod(objects)).containsExactly("apple", "aubergine");
}
static class PrePostSecured {
@PreFilter("filterObject.startsWith('a')")
List<String> preFilterMethod(List<String> objects) {
return objects;
}
}
}
@@ -1,143 +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.method.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.core.context.SecurityContextHolder;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Luke Taylor
* @since 3.0.3
*/
public class SecuredAspectTests {
private TestingAuthenticationToken anne = new TestingAuthenticationToken("anne", "", "ROLE_A");
private MethodInterceptor interceptor;
private SecuredImpl secured = new SecuredImpl();
private SecuredImplSubclass securedSub = new SecuredImplSubclass();
@BeforeEach
public final void setUp() {
MockitoAnnotations.initMocks(this);
this.interceptor = AuthorizationManagerBeforeMethodInterceptor.secured();
SecuredAspect secAspect = SecuredAspect.aspectOf();
secAspect.setSecurityInterceptor(this.interceptor);
}
@AfterEach
public void clearContext() {
SecurityContextHolder.clearContext();
}
@Test
public void securedInterfaceMethodAllowsAllAccess() {
this.secured.securedMethod();
}
@Test
public void securedClassMethodDeniesUnauthenticatedAccess() {
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
.isThrownBy(() -> this.secured.securedClassMethod());
}
@Test
public void securedClassMethodAllowsAccessToRoleA() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
this.secured.securedClassMethod();
}
@Test
public void internalPrivateCallIsIntercepted() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.secured.publicCallsPrivate());
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.securedSub.publicCallsPrivate());
}
@Test
public void protectedMethodIsIntercepted() {
SecurityContextHolder.getContext().setAuthentication(this.anne);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.secured.protectedMethod());
}
@Test
public void overriddenProtectedMethodIsNotIntercepted() {
// AspectJ doesn't inherit annotations
this.securedSub.protectedMethod();
}
interface SecuredInterface {
@Secured("ROLE_X")
void securedMethod();
}
static class SecuredImpl implements SecuredInterface {
// Not really secured because AspectJ doesn't inherit annotations from interfaces
@Override
public void securedMethod() {
}
@Secured("ROLE_A")
void securedClassMethod() {
}
@Secured("ROLE_X")
private void privateMethod() {
}
@Secured("ROLE_X")
protected void protectedMethod() {
}
@Secured("ROLE_X")
void publicCallsPrivate() {
privateMethod();
}
}
static class SecuredImplSubclass extends SecuredImpl {
@Override
protected void protectedMethod() {
}
@Override
public void publicCallsPrivate() {
super.publicCallsPrivate();
}
}
}
+22 -8
View File
@@ -3,8 +3,8 @@ import io.spring.gradle.IncludeRepoTask
buildscript {
dependencies {
classpath "io.spring.javaformat:spring-javaformat-gradle-plugin:$springJavaformatVersion"
classpath 'io.spring.nohttp:nohttp-gradle:0.0.10'
classpath "io.freefair.gradle:aspectj-plugin:6.5.1"
classpath 'io.spring.nohttp:nohttp-gradle:0.0.11'
classpath "io.freefair.gradle:aspectj-plugin:6.4.3.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "com.netflix.nebula:nebula-project-plugin:8.2.0"
}
@@ -104,9 +104,16 @@ updateDependenciesSettings {
majorVersionBump()
minorVersionBump()
releaseCandidatesVersions()
milestoneVersions()
alphaBetaVersions()
snapshotVersions()
addRule { components ->
components.withModule("commons-codec:commons-codec") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("commons-codec updates break saml tests");
}
}
components.withModule("org.python:jython") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
@@ -127,6 +134,18 @@ updateDependenciesSettings {
selection.reject("org.opensaml maintains two different versions, so it must be updated manually");
}
}
components.withModule("io.spring.javaformat:spring-javaformat-gradle-plugin") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("spring-javaformat-gradle-plugin updates break checkstyle");
}
}
components.withModule("io.spring.javaformat:spring-javaformat-checkstyle") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("spring-javaformat-checkstyle updates break checkstyle");
}
}
}
}
}
@@ -138,6 +157,7 @@ subprojects {
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
options.compilerArgs.add("-parameters")
options.release = 8
}
}
@@ -166,12 +186,6 @@ allprojects {
}
}
}
tasks.withType(JavaCompile).configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(8)
}
}
}
if (hasProperty('buildScan')) {
+2 -2
View File
@@ -93,13 +93,13 @@ dependencies {
implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
implementation 'com.github.spullara.mustache.java:compiler:0.9.4'
implementation 'io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.15'
implementation 'io.spring.nohttp:nohttp-gradle:0.0.10'
implementation 'io.spring.nohttp:nohttp-gradle:0.0.11'
implementation 'net.sourceforge.htmlunit:htmlunit:2.37.0'
implementation 'org.hidetake:gradle-ssh-plugin:2.10.1'
implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.29.0'
implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation platform('org.junit:junit-bom:5.8.2')
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
testImplementation "org.junit.jupiter:junit-jupiter-engine"
@@ -36,7 +36,7 @@ class CheckstylePlugin implements Plugin<Project> {
if (checkstyleDir.exists() && checkstyleDir.directory) {
project.getPluginManager().apply('checkstyle')
project.dependencies.add('checkstyle', 'io.spring.javaformat:spring-javaformat-checkstyle:0.0.15')
project.dependencies.add('checkstyle', 'io.spring.nohttp:nohttp-checkstyle:0.0.10')
project.dependencies.add('checkstyle', 'io.spring.nohttp:nohttp-checkstyle:0.0.11')
project.checkstyle {
configDirectory = checkstyleDir
@@ -62,6 +62,33 @@ public class SchemaDeployPlugin implements Plugin<Project> {
execute "rm -f $tempPath*.zip"
execute "rm -rf $extractPath*"
execute "mv $tempPath/* $extractPath"
/*
* Copy spring-security-oauth schemas so that legacy projects using the "http" scheme can
* resolve the following schema locations:
*
* - http://www.springframework.org/schema/security/spring-security-oauth-1.0.xsd
* - http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
* - http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
*
* Note: The directory:
* https://www.springframework.org/schema/security/
*
* is a symbolic link pointing to:
* https://docs.spring.io/autorepo/schema/spring-security/current/security/
*
* which in turn points to the latest:
* https://docs.spring.io/autorepo/schema/spring-security/$version/security/
*
* with the help of the autoln command which is run regularly via a cron job.
*
* See https://github.com/spring-io/autoln for more info.
*/
if (name == "spring-security") {
def springSecurityOauthPath = "/var/www/domains/spring.io/docs/htdocs/autorepo/schema/spring-security-oauth/current/security"
execute "cp $springSecurityOauthPath/* ${extractPath}security"
}
execute "chmod -R g+w $extractPath"
}
}
@@ -0,0 +1,82 @@
/*
* Copyright 2020-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.github.user;
import java.io.IOException;
import com.google.gson.Gson;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* @author Steve Riesenberg
*/
public class GitHubUserApi {
private String baseUrl = "https://api.github.com";
private final OkHttpClient httpClient;
private Gson gson = new Gson();
public GitHubUserApi(String gitHubAccessToken) {
this.httpClient = new OkHttpClient.Builder()
.addInterceptor(new AuthorizationInterceptor(gitHubAccessToken))
.build();
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
/**
* Retrieve a GitHub user by the personal access token.
*
* @return The GitHub user
*/
public User getUser() {
String url = this.baseUrl + "/user";
Request request = new Request.Builder().url(url).get().build();
try (Response response = this.httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException(
String.format("Unable to retrieve GitHub user." +
" Please check the personal access token and try again." +
" Got response %s", response));
}
return this.gson.fromJson(response.body().charStream(), User.class);
} catch (IOException ex) {
throw new RuntimeException("Unable to retrieve GitHub user.", ex);
}
}
private static class AuthorizationInterceptor implements Interceptor {
private final String token;
public AuthorizationInterceptor(String token) {
this.token = token;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + this.token)
.build();
return chain.proceed(request);
}
}
}
@@ -0,0 +1,53 @@
package org.springframework.gradle.github.user;
/**
* @author Steve Riesenberg
*/
public class User {
private Long id;
private String login;
private String name;
private String url;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getLogin() {
return this.login;
}
public void setLogin(String login) {
this.login = login;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", login='" + login + '\'' +
", name='" + name + '\'' +
", url='" + url + '\'' +
'}';
}
}
@@ -26,14 +26,14 @@ import java.util.Base64;
* Implements necessary calls to the Sagan API See https://spring.io/restdocs/index.html
*/
public class SaganApi {
private String baseUrl = "https://spring.io/api";
private String baseUrl = "https://api.spring.io";
private OkHttpClient client;
private Gson gson = new Gson();
public SaganApi(String gitHubToken) {
public SaganApi(String username, String gitHubToken) {
this.client = new OkHttpClient.Builder()
.addInterceptor(new BasicInterceptor("not-used", gitHubToken))
.addInterceptor(new BasicInterceptor(username, gitHubToken))
.build();
}
@@ -20,6 +20,9 @@ import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.springframework.gradle.github.user.GitHubUserApi;
import org.springframework.gradle.github.user.User;
public class SaganCreateReleaseTask extends DefaultTask {
@Input
@@ -35,11 +38,22 @@ public class SaganCreateReleaseTask extends DefaultTask {
@TaskAction
public void saganCreateRelease() {
SaganApi sagan = new SaganApi(this.gitHubAccessToken);
GitHubUserApi github = new GitHubUserApi(this.gitHubAccessToken);
User user = github.getUser();
// Antora reference docs URLs for snapshots do not contain -SNAPSHOT
String referenceDocUrl = this.referenceDocUrl;
if (this.version.endsWith("-SNAPSHOT")) {
referenceDocUrl = this.referenceDocUrl
.replace("{version}", this.version)
.replace("-SNAPSHOT", "");
}
SaganApi sagan = new SaganApi(user.getLogin(), this.gitHubAccessToken);
Release release = new Release();
release.setVersion(this.version);
release.setApiDocUrl(this.apiDocUrl);
release.setReferenceDocUrl(this.referenceDocUrl);
release.setReferenceDocUrl(referenceDocUrl);
sagan.createReleaseForProject(release, this.projectName);
}
@@ -20,6 +20,9 @@ import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.springframework.gradle.github.user.GitHubUserApi;
import org.springframework.gradle.github.user.User;
public class SaganDeleteReleaseTask extends DefaultTask {
@Input
@@ -31,7 +34,10 @@ public class SaganDeleteReleaseTask extends DefaultTask {
@TaskAction
public void saganCreateRelease() {
SaganApi sagan = new SaganApi(this.gitHubAccessToken);
GitHubUserApi github = new GitHubUserApi(this.gitHubAccessToken);
User user = github.getUser();
SaganApi sagan = new SaganApi(user.getLogin(), this.gitHubAccessToken);
sagan.deleteReleaseForProject(this.version, this.projectName);
}
@@ -42,7 +42,7 @@ public class SaganApiTests {
public void setup() throws Exception {
this.server = new MockWebServer();
this.server.start();
this.sagan = new SaganApi("mock-oauth-token");
this.sagan = new SaganApi("user", "mock-oauth-token");
this.baseUrl = this.server.url("/api").toString();
this.sagan.setBaseUrl(this.baseUrl);
}
@@ -63,7 +63,7 @@ public class SaganApiTests {
RecordedRequest request = this.server.takeRequest(1, TimeUnit.SECONDS);
assertThat(request.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/projects/spring-security/releases");
assertThat(request.getMethod()).isEqualToIgnoringCase("post");
assertThat(request.getHeaders().get("Authorization")).isEqualTo("Basic bm90LXVzZWQ6bW9jay1vYXV0aC10b2tlbg==");
assertThat(request.getHeaders().get("Authorization")).isEqualTo("Basic dXNlcjptb2NrLW9hdXRoLXRva2Vu");
assertThat(request.getBody().readString(Charset.defaultCharset())).isEqualToIgnoringWhitespace("{\n" +
" \"version\":\"5.6.0-SNAPSHOT\",\n" +
" \"current\":false,\n" +
@@ -79,7 +79,7 @@ public class SaganApiTests {
RecordedRequest request = this.server.takeRequest(1, TimeUnit.SECONDS);
assertThat(request.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/projects/spring-security/releases/5.6.0-SNAPSHOT");
assertThat(request.getMethod()).isEqualToIgnoringCase("delete");
assertThat(request.getHeaders().get("Authorization")).isEqualTo("Basic bm90LXVzZWQ6bW9jay1vYXV0aC10b2tlbg==");
assertThat(request.getHeaders().get("Authorization")).isEqualTo("Basic dXNlcjptb2NrLW9hdXRoLXRva2Vu");
assertThat(request.getBody().readString(Charset.defaultCharset())).isEmpty();
}
}
@@ -0,0 +1,106 @@
/*
* Copyright 2020-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.github.user;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Steve Riesenberg
*/
public class GitHubUserApiTests {
private GitHubUserApi gitHubUserApi;
private MockWebServer server;
private String baseUrl;
@BeforeEach
public void setup() throws Exception {
this.server = new MockWebServer();
this.server.start();
this.baseUrl = this.server.url("/api").toString();
this.gitHubUserApi = new GitHubUserApi("mock-oauth-token");
this.gitHubUserApi.setBaseUrl(this.baseUrl);
}
@AfterEach
public void cleanup() throws Exception {
this.server.shutdown();
}
@Test
public void getUserWhenValidParametersThenSuccess() {
// @formatter:off
String responseJson = "{\n" +
" \"avatar_url\": \"https://avatars.githubusercontent.com/u/583231?v=4\",\n" +
" \"bio\": null,\n" +
" \"blog\": \"https://github.blog\",\n" +
" \"company\": \"@github\",\n" +
" \"created_at\": \"2011-01-25T18:44:36Z\",\n" +
" \"email\": null,\n" +
" \"events_url\": \"https://api.github.com/users/octocat/events{/privacy}\",\n" +
" \"followers\": 8481,\n" +
" \"followers_url\": \"https://api.github.com/users/octocat/followers\",\n" +
" \"following\": 9,\n" +
" \"following_url\": \"https://api.github.com/users/octocat/following{/other_user}\",\n" +
" \"gists_url\": \"https://api.github.com/users/octocat/gists{/gist_id}\",\n" +
" \"gravatar_id\": \"\",\n" +
" \"hireable\": null,\n" +
" \"html_url\": \"https://github.com/octocat\",\n" +
" \"id\": 583231,\n" +
" \"location\": \"San Francisco\",\n" +
" \"login\": \"octocat\",\n" +
" \"name\": \"The Octocat\",\n" +
" \"node_id\": \"MDQ6VXNlcjU4MzIzMQ==\",\n" +
" \"organizations_url\": \"https://api.github.com/users/octocat/orgs\",\n" +
" \"public_gists\": 8,\n" +
" \"public_repos\": 8,\n" +
" \"received_events_url\": \"https://api.github.com/users/octocat/received_events\",\n" +
" \"repos_url\": \"https://api.github.com/users/octocat/repos\",\n" +
" \"site_admin\": false,\n" +
" \"starred_url\": \"https://api.github.com/users/octocat/starred{/owner}{/repo}\",\n" +
" \"subscriptions_url\": \"https://api.github.com/users/octocat/subscriptions\",\n" +
" \"twitter_username\": null,\n" +
" \"type\": \"User\",\n" +
" \"updated_at\": \"2023-02-25T12:14:58Z\",\n" +
" \"url\": \"https://api.github.com/users/octocat\"\n" +
"}";
// @formatter:on
this.server.enqueue(new MockResponse().setBody(responseJson));
User user = this.gitHubUserApi.getUser();
assertThat(user.getId()).isEqualTo(583231);
assertThat(user.getLogin()).isEqualTo("octocat");
assertThat(user.getName()).isEqualTo("The Octocat");
assertThat(user.getUrl()).isEqualTo("https://api.github.com/users/octocat");
}
@Test
public void getUserWhenErrorResponseThenException() {
this.server.enqueue(new MockResponse().setResponseCode(400));
// @formatter:off
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> this.gitHubUserApi.getUser());
// @formatter:on
}
}
@@ -46,6 +46,7 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* Tests {@link CasAuthenticationFilter}.
@@ -176,7 +177,7 @@ public class CasAuthenticationFilterTests {
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull()
.withFailMessage("Authentication should not be null");
verify(chain).doFilter(request, response);
verifyNoMoreInteractions(successHandler);
verifyZeroInteractions(successHandler);
// validate for when the filterProcessUrl matches
filter.setFilterProcessesUrl(request.getServletPath());
SecurityContextHolder.clearContext();
@@ -228,7 +229,7 @@ public class CasAuthenticationFilterTests {
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl(request.getServletPath());
filter.doFilter(request, response, chain);
verifyNoMoreInteractions(chain);
verifyZeroInteractions(chain);
}
}
+1 -34
View File
@@ -113,6 +113,7 @@ dependencies {
testRuntimeOnly 'org.hsqldb:hsqldb'
}
rncToXsd {
rncDir = file('src/main/resources/org/springframework/security/config/')
xsdDir = rncDir
@@ -129,37 +130,3 @@ tasks.withType(KotlinCompile).configureEach {
}
build.dependsOn rncToXsd
compileTestJava {
exclude "org/springframework/security/config/annotation/web/configurers/saml2/**", "org/springframework/security/config/http/Saml2*"
}
task compileSaml2TestJava(type: JavaCompile) {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(11)
}
source = sourceSets.test.java.srcDirs
include "org/springframework/security/config/annotation/web/configurers/saml2/**", "org/springframework/security/config/http/Saml2*"
classpath = sourceSets.test.compileClasspath
destinationDirectory = new File("${buildDir}/classes/java/test")
options.sourcepath = sourceSets.test.java.getSourceDirectories()
}
task saml2Tests(type: Test) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(11)
}
filter {
includeTestsMatching "org.springframework.security.config.annotation.web.configurers.saml2.*"
}
useJUnitPlatform()
dependsOn compileSaml2TestJava
}
test {
shouldRunAfter saml2Tests
}
tasks.named('check') {
dependsOn saml2Tests
}
@@ -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 5.8. Please update your schema declarations to the 5.8 schema.", element);
+ "with Spring Security 5.7. Please update your schema declarations to the 5.7 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-5\\.8.*.xsd.*")
return schemaLocation.matches("(?m).*spring-security-5\\.7.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -43,9 +43,7 @@ import org.springframework.security.config.annotation.authentication.configurati
*
* @author Rob Winch
* @since 3.2
* @deprecated Use {@link EnableMethodSecurity} instead
*/
@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@@ -26,7 +26,6 @@ import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
/**
*
@@ -70,11 +69,4 @@ public @interface EnableReactiveMethodSecurity {
*/
int order() default Ordered.LOWEST_PRECEDENCE;
/**
* Indicate whether {@link ReactiveAuthorizationManager} based Method Security to be
* used.
* @since 5.8
*/
boolean useAuthorizationManager() default false;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -36,9 +36,7 @@ import org.springframework.core.type.AnnotationMetadata;
*
* @author Rob Winch
* @since 3.2
* @deprecated Use {@link EnableMethodSecurity} instead
*/
@Deprecated
class GlobalMethodSecurityAspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
@@ -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.
@@ -73,8 +73,6 @@ import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.Assert;
/**
@@ -86,11 +84,7 @@ import org.springframework.util.Assert;
* @author Eddú Meléndez
* @since 3.2
* @see EnableGlobalMethodSecurity
* @deprecated Use {@link PrePostMethodSecurityConfiguration},
* {@link SecuredMethodSecurityConfiguration}, or
* {@link Jsr250MethodSecurityConfiguration} instead
*/
@Deprecated
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class GlobalMethodSecurityConfiguration implements ImportAware, SmartInitializingSingleton, BeanFactoryAware {
@@ -107,9 +101,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware, SmartInit
};
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private DefaultMethodSecurityExpressionHandler defaultMethodExpressionHandler = new DefaultMethodSecurityExpressionHandler();
private AuthenticationManager authenticationManager;
@@ -152,7 +143,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware, SmartInit
this.methodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
this.methodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager());
this.methodSecurityInterceptor.setSecurityMetadataSource(methodSecurityMetadataSource);
this.methodSecurityInterceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
RunAsManager runAsManager = runAsManager();
if (runAsManager != null) {
this.methodSecurityInterceptor.setRunAsManager(runAsManager);
@@ -421,12 +411,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware, SmartInit
this.expressionHandler = handlers.get(0);
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.context = beanFactory;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2018 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,9 +34,7 @@ import org.springframework.util.ClassUtils;
*
* @author Rob Winch
* @since 3.2
* @deprecated Use {@link MethodSecuritySelector} instead
*/
@Deprecated
final class GlobalMethodSecuritySelector implements ImportSelector {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@ import org.springframework.security.access.annotation.Jsr250MethodSecurityMetada
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Deprecated
class Jsr250MetadataSourceConfiguration {
@Bean
@@ -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.
@@ -25,8 +25,6 @@ import org.springframework.context.annotation.Role;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.Jsr250AuthorizationManager;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
/**
* {@link Configuration} for enabling JSR-250 Spring Security Method Security.
@@ -42,16 +40,10 @@ final class Jsr250MethodSecurityConfiguration {
private final Jsr250AuthorizationManager jsr250AuthorizationManager = new Jsr250AuthorizationManager();
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor jsr250AuthorizationMethodInterceptor() {
AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
.jsr250(this.jsr250AuthorizationManager);
interceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
return interceptor;
return AuthorizationManagerBeforeMethodInterceptor.jsr250(this.jsr250AuthorizationManager);
}
@Autowired(required = false)
@@ -59,9 +51,4 @@ final class Jsr250MethodSecurityConfiguration {
this.jsr250AuthorizationManager.setRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
}
@@ -1,78 +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.method.configuration;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
/**
* Registers an
* {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
* AnnotationAwareAspectJAutoProxyCreator} against the current
* {@link BeanDefinitionRegistry} as appropriate based on a given @
* {@link EnableMethodSecurity} annotation.
*
* <p>
* Note: This class is necessary because AspectJAutoProxyRegistrar only supports
* EnableAspectJAutoProxy.
* </p>
*
* @author Josh Cummings
* @since 5.8
*/
class MethodSecurityAspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableMethodSecurity#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registerBeanDefinition("preFilterAuthorizationMethodInterceptor",
"org.springframework.security.authorization.method.aspectj.PreFilterAspect", "preFilterAspect$0",
registry);
registerBeanDefinition("postFilterAuthorizationMethodInterceptor",
"org.springframework.security.authorization.method.aspectj.PostFilterAspect", "postFilterAspect$0",
registry);
registerBeanDefinition("preAuthorizeAuthorizationMethodInterceptor",
"org.springframework.security.authorization.method.aspectj.PreAuthorizeAspect", "preAuthorizeAspect$0",
registry);
registerBeanDefinition("postAuthorizeAuthorizationMethodInterceptor",
"org.springframework.security.authorization.method.aspectj.PostAuthorizeAspect",
"postAuthorizeAspect$0", registry);
registerBeanDefinition("securedAuthorizationMethodInterceptor",
"org.springframework.security.authorization.method.aspectj.SecuredAspect", "securedAspect$0", registry);
}
private void registerBeanDefinition(String beanName, String aspectClassName, String aspectBeanName,
BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(beanName)) {
return;
}
BeanDefinition interceptor = registry.getBeanDefinition(beanName);
BeanDefinitionBuilder aspect = BeanDefinitionBuilder.rootBeanDefinition(aspectClassName);
aspect.setFactoryMethod("aspectOf");
aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
aspect.addPropertyValue("securityInterceptor", interceptor);
registry.registerBeanDefinition(aspectBeanName, aspect.getBeanDefinition());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2018 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.
@@ -32,9 +32,7 @@ import org.springframework.util.MultiValueMap;
* @author Rob Winch
* @since 4.0.2
* @see GlobalMethodSecuritySelector
* @deprecated Use {@link MethodSecuritySelector} instead
*/
@Deprecated
class MethodSecurityMetadataSourceAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
/**
@@ -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.
@@ -62,17 +62,11 @@ final class MethodSecuritySelector implements ImportSelector {
private static final String[] IMPORTS = new String[] { AutoProxyRegistrar.class.getName() };
private static final String[] ASPECTJ_IMPORTS = new String[] {
MethodSecurityAspectJAutoProxyRegistrar.class.getName() };
@Override
protected String[] selectImports(@NonNull AdviceMode adviceMode) {
if (adviceMode == AdviceMode.PROXY) {
return IMPORTS;
}
if (adviceMode == AdviceMode.ASPECTJ) {
return ASPECTJ_IMPORTS;
}
throw new IllegalStateException("AdviceMode '" + adviceMode + "' is not supported");
}
@@ -34,7 +34,6 @@ 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.context.SecurityContextHolderStrategy;
/**
* Base {@link Configuration} for enabling Spring Security Method Security.
@@ -110,14 +109,6 @@ final class PrePostMethodSecurityConfiguration {
this.postFilterAuthorizationMethodInterceptor.setExpressionHandler(methodSecurityExpressionHandler);
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
this.preFilterAuthorizationMethodInterceptor.setSecurityContextHolderStrategy(strategy);
this.preAuthorizeAuthorizationMethodInterceptor.setSecurityContextHolderStrategy(strategy);
this.postAuthorizeAuthorizaitonMethodInterceptor.setSecurityContextHolderStrategy(strategy);
this.postFilterAuthorizationMethodInterceptor.setSecurityContextHolderStrategy(strategy);
}
@Autowired(required = false)
void setGrantedAuthorityDefaults(GrantedAuthorityDefaults grantedAuthorityDefaults) {
this.expressionHandler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
@@ -1,87 +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.method.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authorization.method.AuthorizationManagerAfterReactiveMethodInterceptor;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeReactiveMethodInterceptor;
import org.springframework.security.authorization.method.PostAuthorizeReactiveAuthorizationManager;
import org.springframework.security.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor;
import org.springframework.security.authorization.method.PreAuthorizeReactiveAuthorizationManager;
import org.springframework.security.authorization.method.PreFilterAuthorizationReactiveMethodInterceptor;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
/**
* Configuration for a {@link ReactiveAuthenticationManager} based Method Security.
*
* @author Evgeniy Cheban
* @since 5.8
*/
@Configuration(proxyBeanMethods = false)
final class ReactiveAuthorizationManagerMethodSecurityConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
PreFilterAuthorizationReactiveMethodInterceptor preFilterInterceptor(
MethodSecurityExpressionHandler expressionHandler) {
return new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorizeInterceptor(
MethodSecurityExpressionHandler expressionHandler) {
PreAuthorizeReactiveAuthorizationManager authorizationManager = new PreAuthorizeReactiveAuthorizationManager(
expressionHandler);
return AuthorizationManagerBeforeReactiveMethodInterceptor.preAuthorize(authorizationManager);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
PostFilterAuthorizationReactiveMethodInterceptor postFilterInterceptor(
MethodSecurityExpressionHandler expressionHandler) {
return new PostFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeInterceptor(
MethodSecurityExpressionHandler expressionHandler) {
PostAuthorizeReactiveAuthorizationManager authorizationManager = new PostAuthorizeReactiveAuthorizationManager(
expressionHandler);
return AuthorizationManagerAfterReactiveMethodInterceptor.postAuthorize(authorizationManager);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler(
@Autowired(required = false) GrantedAuthorityDefaults grantedAuthorityDefaults) {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
if (grantedAuthorityDefaults != null) {
handler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
return handler;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,55 +17,37 @@
package org.springframework.security.config.annotation.method.configuration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.AdviceModeImportSelector;
import org.springframework.context.annotation.AutoProxyRegistrar;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.NonNull;
/**
* @author Rob Winch
* @author Evgeniy Cheban
* @since 5.0
*/
class ReactiveMethodSecuritySelector implements ImportSelector {
private final ImportSelector autoProxy = new AutoProxyRegistrarSelector();
class ReactiveMethodSecuritySelector extends AdviceModeImportSelector<EnableReactiveMethodSecurity> {
@Override
public String[] selectImports(AnnotationMetadata importMetadata) {
if (!importMetadata.hasAnnotation(EnableReactiveMethodSecurity.class.getName())) {
return new String[0];
protected String[] selectImports(AdviceMode adviceMode) {
if (adviceMode == AdviceMode.PROXY) {
return getProxyImports();
}
EnableReactiveMethodSecurity annotation = importMetadata.getAnnotations()
.get(EnableReactiveMethodSecurity.class).synthesize();
List<String> imports = new ArrayList<>(Arrays.asList(this.autoProxy.selectImports(importMetadata)));
if (annotation.useAuthorizationManager()) {
imports.add(ReactiveAuthorizationManagerMethodSecurityConfiguration.class.getName());
}
else {
imports.add(ReactiveMethodSecurityConfiguration.class.getName());
}
return imports.toArray(new String[0]);
throw new IllegalStateException("AdviceMode " + adviceMode + " is not supported");
}
private static final class AutoProxyRegistrarSelector
extends AdviceModeImportSelector<EnableReactiveMethodSecurity> {
private static final String[] IMPORTS = new String[] { AutoProxyRegistrar.class.getName() };
@Override
protected String[] selectImports(@NonNull AdviceMode adviceMode) {
if (adviceMode == AdviceMode.PROXY) {
return IMPORTS;
}
throw new IllegalStateException("AdviceMode " + adviceMode + " is not supported");
}
/**
* Return the imports to use if the {@link AdviceMode} is set to
* {@link AdviceMode#PROXY}.
* <p>
* Take care of adding the necessary JSR-107 import if it is available.
*/
private String[] getProxyImports() {
List<String> result = new ArrayList<>();
result.add(AutoProxyRegistrar.class.getName());
result.add(ReactiveMethodSecurityConfiguration.class.getName());
return result.toArray(new String[0]);
}
}
@@ -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.
@@ -17,15 +17,12 @@
package org.springframework.security.config.annotation.method.configuration;
import org.springframework.aop.Advisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
/**
* {@link Configuration} for enabling {@link Secured} Spring Security Method Security.
@@ -39,20 +36,10 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
final class SecuredMethodSecurityConfiguration {
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor securedAuthorizationMethodInterceptor() {
AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor.secured();
interceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
return interceptor;
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.securityContextHolderStrategy = securityContextHolderStrategy;
return AuthorizationManagerBeforeMethodInterceptor.secured();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,7 +35,6 @@ import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatche
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
/**
@@ -51,21 +50,12 @@ public abstract class AbstractRequestMatcherRegistry<C> {
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
private static final boolean mvcPresent;
private static final RequestMatcher ANY_REQUEST = AnyRequestMatcher.INSTANCE;
private ApplicationContext context;
private boolean anyRequestConfigured = false;
static {
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
AbstractRequestMatcherRegistry.class.getClassLoader());
}
protected final void setApplicationContext(ApplicationContext context) {
this.context = context;
}
@@ -95,9 +85,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* instances.
* @param method the {@link HttpMethod} to use for any {@link HttpMethod}.
* @return the object that is chained after creating the {@link RequestMatcher}
* @deprecated use {@link #requestMatchers(HttpMethod)} instead
*/
@Deprecated
public C antMatchers(HttpMethod method) {
return antMatchers(method, "/**");
}
@@ -111,9 +99,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* @param antPatterns the ant patterns to create. If {@code null} or empty, then
* matches on nothing.
* @return the object that is chained after creating the {@link RequestMatcher}
* @deprecated use {@link #requestMatchers(HttpMethod, String...)} instead
*/
@Deprecated
public C antMatchers(HttpMethod method, String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(method, antPatterns));
@@ -126,9 +112,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* @param antPatterns the ant patterns to create
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} from
* @return the object that is chained after creating the {@link RequestMatcher}
* @deprecated use {@link #requestMatchers(String...)} instead
*/
@Deprecated
public C antMatchers(String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
@@ -148,9 +132,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* @param mvcPatterns the patterns to match on. The rules for matching are defined by
* Spring MVC
* @return the object that is chained after creating the {@link RequestMatcher}.
* @deprecated use {@link #requestMatchers(String...)} instead
*/
@Deprecated
public abstract C mvcMatchers(String... mvcPatterns);
/**
@@ -168,9 +150,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* @param mvcPatterns the patterns to match on. The rules for matching are defined by
* Spring MVC
* @return the object that is chained after creating the {@link RequestMatcher}.
* @deprecated use {@link #requestMatchers(HttpMethod, String...)} instead
*/
@Deprecated
public abstract C mvcMatchers(HttpMethod method, String... mvcPatterns);
/**
@@ -210,10 +190,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* @param regexPatterns the regular expressions to create
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher} from
* @return the object that is chained after creating the {@link RequestMatcher}
* @deprecated use {@link #requestMatchers(RequestMatcher...)} with a
* {@link RegexRequestMatcher} instead
*/
@Deprecated
public C regexMatchers(HttpMethod method, String... regexPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.regexMatchers(method, regexPatterns));
@@ -226,10 +203,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* @param regexPatterns the regular expressions to create
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher} from
* @return the object that is chained after creating the {@link RequestMatcher}
* @deprecated use {@link #requestMatchers(RequestMatcher...)} with a
* {@link RegexRequestMatcher} instead
*/
@Deprecated
public C regexMatchers(String... regexPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.regexMatchers(regexPatterns));
@@ -276,81 +250,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
return chainRequestMatchers(Arrays.asList(requestMatchers));
}
/**
* <p>
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
* {@link MvcRequestMatcher} that also specifies a specific {@link HttpMethod} to
* match on. This matcher will use the same rules that Spring MVC uses for matching.
* For example, often times a mapping of the path "/path" will match on "/path",
* "/path/", "/path.html", etc. If the {@link HandlerMappingIntrospector} is not
* available, maps to an {@link AntPathRequestMatcher}.
* </p>
* <p>
* If a specific {@link RequestMatcher} must be specified, use
* {@link #requestMatchers(RequestMatcher...)} instead
* </p>
* @param method the {@link HttpMethod} to use or {@code null} for any
* {@link HttpMethod}.
* @param patterns the patterns to match on. The rules for matching are defined by
* Spring MVC if {@link MvcRequestMatcher} is used
* @return the object that is chained after creating the {@link RequestMatcher}.
* @since 5.8
*/
public C requestMatchers(HttpMethod method, String... patterns) {
List<RequestMatcher> matchers = new ArrayList<>();
if (mvcPresent) {
matchers.addAll(createMvcMatchers(method, patterns));
}
else {
matchers.addAll(RequestMatchers.antMatchers(method, patterns));
}
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
}
/**
* <p>
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
* {@link MvcRequestMatcher} that does not care which {@link HttpMethod} is used. This
* matcher will use the same rules that Spring MVC uses for matching. For example,
* often times a mapping of the path "/path" will match on "/path", "/path/",
* "/path.html", etc. If the {@link HandlerMappingIntrospector} is not available, maps
* to an {@link AntPathRequestMatcher}.
* </p>
* <p>
* If a specific {@link RequestMatcher} must be specified, use
* {@link #requestMatchers(RequestMatcher...)} instead
* </p>
* @param patterns the patterns to match on. The rules for matching are defined by
* Spring MVC if {@link MvcRequestMatcher} is used
* @return the object that is chained after creating the {@link RequestMatcher}.
* @since 5.8
*/
public C requestMatchers(String... patterns) {
return requestMatchers(null, patterns);
}
/**
* <p>
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
* {@link MvcRequestMatcher} that matches on a specific {@link HttpMethod}. This
* matcher will use the same rules that Spring MVC uses for matching. For example,
* often times a mapping of the path "/path" will match on "/path", "/path/",
* "/path.html", etc. If the {@link HandlerMappingIntrospector} is not available, maps
* to an {@link AntPathRequestMatcher}.
* </p>
* <p>
* If a specific {@link RequestMatcher} must be specified, use
* {@link #requestMatchers(RequestMatcher...)} instead
* </p>
* @param method the {@link HttpMethod} to use or {@code null} for any
* {@link HttpMethod}.
* @return the object that is chained after creating the {@link RequestMatcher}.
* @since 5.8
*/
public C requestMatchers(HttpMethod method) {
return requestMatchers(method, "/**");
}
/**
* Subclasses should implement this method for returning the object that is chained to
* the creation of the {@link RequestMatcher} instances.
@@ -23,7 +23,6 @@ import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.access.ExceptionTranslationFilter;
@@ -142,7 +141,7 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
* <li>{@link org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter}</li>
* <li>{@link ConcurrentSessionFilter}</li>
* <li>{@link DigestAuthenticationFilter}</li>
* <li>{@link BearerTokenAuthenticationFilter}</li>
* <li>{@link org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter}</li>
* <li>{@link BasicAuthenticationFilter}</li>
* <li>{@link RequestCacheAwareFilter}</li>
* <li>{@link SecurityContextHolderAwareRequestFilter}</li>
@@ -85,7 +85,7 @@ final class FilterOrderRegistration {
"org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
order.next());
this.filterToOrder.put(
"org.springframework.security.saml2.provider.service.web.Saml2WebSsoAuthenticationRequestFilter",
"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter",
order.next());
put(X509AuthenticationFilter.class, order.next());
put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
@@ -93,7 +93,7 @@ final class FilterOrderRegistration {
this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
order.next());
this.filterToOrder.put(
"org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter",
"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter",
order.next());
put(UsernamePasswordAuthenticationFilter.class, order.next());
order.next(); // gh-8105
@@ -103,7 +103,7 @@ final class FilterOrderRegistration {
put(ConcurrentSessionFilter.class, order.next());
put(DigestAuthenticationFilter.class, order.next());
this.filterToOrder.put(
"org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter",
"org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter",
order.next());
put(BasicAuthenticationFilter.class, order.next());
put(RequestCacheAwareFilter.class, order.next());
@@ -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.
@@ -28,7 +28,6 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered;
@@ -93,7 +92,6 @@ import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
@@ -119,7 +117,7 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* http.authorizeHttpRequests().requestMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;).and().formLogin();
* http.authorizeRequests().antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;).and().formLogin();
* return http.build();
* }
*
@@ -143,12 +141,6 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
private static final boolean mvcPresent;
private final RequestMatcherConfigurer requestMatcherConfigurer;
private List<OrderedFilter> filters = new ArrayList<>();
@@ -159,10 +151,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
private AuthenticationManager authenticationManager;
static {
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, HttpSecurity.class.getClassLoader());
}
/**
* Creates a new instance
* @param objectPostProcessor the {@link ObjectPostProcessor} that should be used
@@ -1293,10 +1281,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* </pre>
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations
* @throws Exception
* @deprecated Use {@link #authorizeHttpRequests()} instead
* @see #requestMatcher(RequestMatcher)
*/
@Deprecated
public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests()
throws Exception {
ApplicationContext context = getContext();
@@ -1409,10 +1395,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* for the {@link ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry}
* @return the {@link HttpSecurity} for further customizations
* @throws Exception
* @deprecated Use {@link #authorizeHttpRequests} instead
* @see #requestMatcher(RequestMatcher)
*/
@Deprecated
public HttpSecurity authorizeRequests(
Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer)
throws Exception {
@@ -3270,7 +3254,12 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
}
private HttpSecurity addFilterAtOffsetOf(Filter filter, int offset, Class<? extends Filter> registeredFilter) {
int order = this.filterOrders.getOrder(registeredFilter) + offset;
Integer registeredFilterOrder = this.filterOrders.getOrder(registeredFilter);
if (registeredFilterOrder == null) {
throw new IllegalArgumentException(
"The Filter class " + registeredFilter.getName() + " does not have a registered order");
}
int order = registeredFilterOrder + offset;
this.filters.add(new OrderedFilter(filter, order));
this.filterOrders.put(filter.getClass(), order);
return this;
@@ -3427,9 +3416,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
* </pre>
* @return the {@link RequestMatcherConfigurer} for further customizations
* @deprecated use {@link #securityMatchers()} instead
*/
@Deprecated
public RequestMatcherConfigurer requestMatchers() {
return this.requestMatcherConfigurer;
}
@@ -3561,9 +3548,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @param requestMatcherCustomizer the {@link Customizer} to provide more options for
* the {@link RequestMatcherConfigurer}
* @return the {@link HttpSecurity} for further customizations
* @deprecated use {@link #securityMatchers(Customizer)} instead
*/
@Deprecated
public HttpSecurity requestMatchers(Customizer<RequestMatcherConfigurer> requestMatcherCustomizer) {
requestMatcherCustomizer.customize(this.requestMatcherConfigurer);
return HttpSecurity.this;
@@ -3583,337 +3568,15 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @param requestMatcher the {@link RequestMatcher} to use (i.e. new
* AntPathRequestMatcher("/admin/**","GET") )
* @return the {@link HttpSecurity} for further customizations
* @deprecated use {@link #securityMatcher(RequestMatcher)} instead
* @see #requestMatchers()
* @see #antMatcher(String)
* @see #regexMatcher(String)
*/
@Deprecated
public HttpSecurity requestMatcher(RequestMatcher requestMatcher) {
this.requestMatcher = requestMatcher;
return this;
}
/**
* Allows specifying which {@link HttpServletRequest} instances this
* {@link HttpSecurity} will be invoked on. This method allows for easily invoking the
* {@link HttpSecurity} for multiple different {@link RequestMatcher} instances. If
* only a single {@link RequestMatcher} is necessary consider using
* {@link #securityMatcher(String...)}, or {@link #securityMatcher(RequestMatcher)}.
*
* <p>
* Invoking {@link #securityMatchers()} will not override previous invocations of
* {@link #securityMatchers()}}, {@link #securityMatchers(Customizer)}
* {@link #securityMatcher(String...)} and {@link #securityMatcher(RequestMatcher)}
* </p>
*
* <h3>Example Configurations</h3>
*
* The following configuration enables the {@link HttpSecurity} for URLs that begin
* with "/api/" or "/oauth/".
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class RequestMatchersSecurityConfig {
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* http
* .securityMatchers((matchers) -&gt; matchers
* .requestMatchers(&quot;/api/**&quot;, &quot;/oauth/**&quot;)
* )
* .authorizeHttpRequests((authorize) -&gt; authorize
* anyRequest().hasRole(&quot;USER&quot;)
* )
* .httpBasic(withDefaults());
* return http.build();
* }
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;user&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user);
* }
* }
* </pre>
*
* The configuration below is the same as the previous configuration.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class RequestMatchersSecurityConfig {
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* http
* .securityMatchers((matchers) -&gt; matchers
* .requestMatchers(&quot;/api/**&quot;)
* .requestMatchers(&quot;/oauth/**&quot;)
* )
* .authorizeHttpRequests((authorize) -&gt; authorize
* anyRequest().hasRole(&quot;USER&quot;)
* )
* .httpBasic(withDefaults());
* return http.build();
* }
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;user&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user);
* }
* }
* </pre>
*
* The configuration below is also the same as the above configuration.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class RequestMatchersSecurityConfig {
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* http
* .securityMatchers((matchers) -&gt; matchers
* .requestMatchers(&quot;/api/**&quot;)
* )
* .securityMatchers((matchers) -&gt; matchers
* .requestMatchers(&quot;/oauth/**&quot;)
* )
* .authorizeHttpRequests((authorize) -&gt; authorize
* anyRequest().hasRole(&quot;USER&quot;)
* )
* .httpBasic(withDefaults());
* return http.build();
* }
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;user&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user);
* }
* }
* </pre>
* @return the {@link RequestMatcherConfigurer} for further customizations
*/
public RequestMatcherConfigurer securityMatchers() {
return this.requestMatcherConfigurer;
}
/**
* Allows specifying which {@link HttpServletRequest} instances this
* {@link HttpSecurity} will be invoked on. This method allows for easily invoking the
* {@link HttpSecurity} for multiple different {@link RequestMatcher} instances. If
* only a single {@link RequestMatcher} is necessary consider using
* {@link #securityMatcher(String...)}, or {@link #securityMatcher(RequestMatcher)}.
*
* <p>
* Invoking {@link #securityMatchers(Customizer)} will not override previous
* invocations of {@link #securityMatchers()}}, {@link #securityMatchers(Customizer)}
* {@link #securityMatcher(String...)} and {@link #securityMatcher(RequestMatcher)}
* </p>
*
* <h3>Example Configurations</h3>
*
* The following configuration enables the {@link HttpSecurity} for URLs that begin
* with "/api/" or "/oauth/".
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class RequestMatchersSecurityConfig {
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* http
* .securityMatchers((matchers) -&gt; matchers
* .requestMatchers(&quot;/api/**&quot;, &quot;/oauth/**&quot;)
* )
* .authorizeHttpRequests((authorize) -&gt; authorize
* .anyRequest().hasRole(&quot;USER&quot;)
* )
* .httpBasic(withDefaults());
* return http.build();
* }
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;user&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user);
* }
* }
* </pre>
*
* The configuration below is the same as the previous configuration.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class RequestMatchersSecurityConfig {
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* http
* .securityMatchers((matchers) -&gt; matchers
* .requestMatchers(&quot;/api/**&quot;)
* .requestMatchers(&quot;/oauth/**&quot;)
* )
* .authorizeHttpRequests((authorize) -&gt; authorize
* .anyRequest().hasRole(&quot;USER&quot;)
* )
* .httpBasic(withDefaults());
* return http.build();
* }
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;user&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user);
* }
* }
* </pre>
*
* The configuration below is also the same as the above configuration.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class RequestMatchersSecurityConfig {
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* http
* .securityMatchers((matchers) -&gt; matchers
* .requestMatchers(&quot;/api/**&quot;)
* )
* .securityMatchers((matchers) -&gt; matchers
* .requestMatchers(&quot;/oauth/**&quot;)
* )
* .authorizeHttpRequests((authorize) -&gt; authorize
* .anyRequest().hasRole(&quot;USER&quot;)
* )
* .httpBasic(withDefaults());
* return http.build();
* }
*
* &#064;Bean
* public UserDetailsService userDetailsService() {
* UserDetails user = User.withDefaultPasswordEncoder()
* .username(&quot;user&quot;)
* .password(&quot;password&quot;)
* .roles(&quot;USER&quot;)
* .build();
* return new InMemoryUserDetailsManager(user);
* }
* }
* </pre>
* @param requestMatcherCustomizer the {@link Customizer} to provide more options for
* the {@link RequestMatcherConfigurer}
* @return the {@link HttpSecurity} for further customizations
*/
public HttpSecurity securityMatchers(Customizer<RequestMatcherConfigurer> requestMatcherCustomizer) {
requestMatcherCustomizer.customize(this.requestMatcherConfigurer);
return HttpSecurity.this;
}
/**
* Allows configuring the {@link HttpSecurity} to only be invoked when matching the
* provided {@link RequestMatcher}. If more advanced configuration is necessary,
* consider using {@link #securityMatchers(Customizer)} ()}.
*
* <p>
* Invoking {@link #securityMatcher(RequestMatcher)} will override previous
* invocations of {@link #requestMatchers()}, {@link #mvcMatcher(String)},
* {@link #antMatcher(String)}, {@link #regexMatcher(String)},
* {@link #requestMatcher(RequestMatcher)}, {@link #securityMatchers(Customizer)},
* {@link #securityMatchers()} and {@link #securityMatcher(String...)}
* </p>
* @param requestMatcher the {@link RequestMatcher} to use (i.e. new
* AntPathRequestMatcher("/admin/**","GET") )
* @return the {@link HttpSecurity} for further customizations
* @see #securityMatcher(String...)
*/
public HttpSecurity securityMatcher(RequestMatcher requestMatcher) {
this.requestMatcher = requestMatcher;
return this;
}
/**
* Allows configuring the {@link HttpSecurity} to only be invoked when matching the
* provided pattern. This method creates a {@link MvcRequestMatcher} if Spring MVC is
* in the classpath or creates an {@link AntPathRequestMatcher} if not. If more
* advanced configuration is necessary, consider using
* {@link #securityMatchers(Customizer)} or {@link #securityMatcher(RequestMatcher)}.
*
* <p>
* Invoking {@link #securityMatcher(String...)} will override previous invocations of
* {@link #mvcMatcher(String)}}, {@link #requestMatchers()},
* {@link #antMatcher(String)}, {@link #regexMatcher(String)}, and
* {@link #requestMatcher(RequestMatcher)}.
* </p>
* @param patterns the pattern to match on (i.e. "/admin/**")
* @return the {@link HttpSecurity} for further customizations
* @see AntPathRequestMatcher
* @see MvcRequestMatcher
*/
public HttpSecurity securityMatcher(String... patterns) {
if (mvcPresent) {
this.requestMatcher = new OrRequestMatcher(createMvcMatchers(patterns));
return this;
}
this.requestMatcher = new OrRequestMatcher(createAntMatchers(patterns));
return this;
}
private List<RequestMatcher> createAntMatchers(String... patterns) {
List<RequestMatcher> matchers = new ArrayList<>(patterns.length);
for (String pattern : patterns) {
matchers.add(new AntPathRequestMatcher(pattern));
}
return matchers;
}
private List<RequestMatcher> createMvcMatchers(String... mvcPatterns) {
ObjectPostProcessor<Object> opp = getContext().getBean(ObjectPostProcessor.class);
if (!getContext().containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME
+ " of type " + HandlerMappingIntrospector.class.getName()
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
}
HandlerMappingIntrospector introspector = getContext().getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
HandlerMappingIntrospector.class);
List<RequestMatcher> matchers = new ArrayList<>(mvcPatterns.length);
for (String mvcPattern : mvcPatterns) {
MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern);
opp.postProcess(matcher);
matchers.add(matcher);
}
return matchers;
}
/**
* Allows configuring the {@link HttpSecurity} to only be invoked when matching the
* provided ant pattern. If more advanced configuration is necessary, consider using
@@ -3927,10 +3590,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* </p>
* @param antPattern the Ant Pattern to match on (i.e. "/admin/**")
* @return the {@link HttpSecurity} for further customizations
* @deprecated use {@link #securityMatcher(String...)} instead
* @see AntPathRequestMatcher
*/
@Deprecated
public HttpSecurity antMatcher(String antPattern) {
return requestMatcher(new AntPathRequestMatcher(antPattern));
}
@@ -3948,10 +3609,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* </p>
* @param mvcPattern the Spring MVC Pattern to match on (i.e. "/admin/**")
* @return the {@link HttpSecurity} for further customizations
* @deprecated use {@link #securityMatcher(String...)} instead
* @see MvcRequestMatcher
*/
@Deprecated
public HttpSecurity mvcMatcher(String mvcPattern) {
HandlerMappingIntrospector introspector = new HandlerMappingIntrospector(getContext());
return requestMatcher(new MvcRequestMatcher(introspector, mvcPattern));
@@ -3970,10 +3629,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* </p>
* @param pattern the Regular Expression to match on (i.e. "/admin/.+")
* @return the {@link HttpSecurity} for further customizations
* @deprecated use {@link #securityMatcher(RequestMatcher)} with a
* {@link RegexRequestMatcher} instead
* @see RegexRequestMatcher
*/
@Deprecated
public HttpSecurity regexMatcher(String pattern) {
return requestMatcher(new RegexRequestMatcher(pattern, null));
}
@@ -4044,22 +3701,14 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
setApplicationContext(context);
}
/**
* @deprecated use {@link #requestMatchers(HttpMethod, String...)} instead
*/
@Override
@Deprecated
public MvcMatchersRequestMatcherConfigurer mvcMatchers(HttpMethod method, String... mvcPatterns) {
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
setMatchers(mvcMatchers);
return new MvcMatchersRequestMatcherConfigurer(getContext(), mvcMatchers, this.matchers);
}
/**
* @deprecated use {@link #requestMatchers(String...)} instead
*/
@Override
@Deprecated
public MvcMatchersRequestMatcherConfigurer mvcMatchers(String... patterns) {
return mvcMatchers(null, patterns);
}
@@ -4072,7 +3721,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
private void setMatchers(List<? extends RequestMatcher> requestMatchers) {
this.matchers.addAll(requestMatchers);
securityMatcher(new OrRequestMatcher(this.matchers));
requestMatcher(new OrRequestMatcher(this.matchers));
}
/**
@@ -138,7 +138,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
* <pre>
* webSecurityBuilder.ignoring()
* // ignore all URLs that start with /resources/ or /static/
* .requestMatchers(&quot;/resources/**&quot;, &quot;/static/**&quot;);
* .antMatchers(&quot;/resources/**&quot;, &quot;/static/**&quot;);
* </pre>
*
* Alternatively this will accomplish the same result:
@@ -146,7 +146,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
* <pre>
* webSecurityBuilder.ignoring()
* // ignore all URLs that start with /resources/ or /static/
* .requestMatchers(&quot;/resources/**&quot;).requestMatchers(&quot;/static/**&quot;);
* .antMatchers(&quot;/resources/**&quot;).antMatchers(&quot;/static/**&quot;);
* </pre>
*
* Multiple invocations of ignoring() are also additive, so the following is also
@@ -155,10 +155,10 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
* <pre>
* webSecurityBuilder.ignoring()
* // ignore all URLs that start with /resources/
* .requestMatchers(&quot;/resources/**&quot;);
* .antMatchers(&quot;/resources/**&quot;);
* webSecurityBuilder.ignoring()
* // ignore all URLs that start with /static/
* .requestMatchers(&quot;/static/**&quot;);
* .antMatchers(&quot;/static/**&quot;);
* // now both URLs that start with /resources/ and /static/ will be ignored
* </pre>
* @return the {@link IgnoredRequestConfigurer} to use for registering request that
@@ -401,9 +401,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
* {@link MvcRequestMatcher#setMethod(HttpMethod)}
*
* @author Rob Winch
* @deprecated use {@link MvcRequestMatcher.Builder} instead
*/
@Deprecated
public final class MvcMatchersIgnoredRequestConfigurer extends IgnoredRequestConfigurer {
private final List<MvcRequestMatcher> mvcMatchers;
@@ -435,22 +433,14 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
setApplicationContext(context);
}
/**
* @deprecated use {@link #requestMatchers(HttpMethod, String...)} instead
*/
@Override
@Deprecated
public MvcMatchersIgnoredRequestConfigurer mvcMatchers(HttpMethod method, String... mvcPatterns) {
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
WebSecurity.this.ignoredRequests.addAll(mvcMatchers);
return new MvcMatchersIgnoredRequestConfigurer(getApplicationContext(), mvcMatchers);
}
/**
* @deprecated use {@link #requestMatchers(String...)} instead
*/
@Override
@Deprecated
public MvcMatchersIgnoredRequestConfigurer mvcMatchers(String... mvcPatterns) {
return mvcMatchers(null, mvcPatterns);
}
@@ -42,12 +42,12 @@ import org.springframework.security.web.SecurityFilterChain;
* public WebSecurityCustomizer webSecurityCustomizer() {
* return (web) -> web.ignoring()
* // Spring Security should completely ignore URLs starting with /resources/
* .requestMatchers(&quot;/resources/**&quot;);
* .antMatchers(&quot;/resources/**&quot;);
* }
*
* &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* http.authorizeRequests().requestMatchers(&quot;/public/**&quot;).permitAll().anyRequest()
* http.authorizeRequests().antMatchers(&quot;/public/**&quot;).permitAll().anyRequest()
* .hasRole(&quot;USER&quot;).and()
* // Possibly more configuration ...
* .formLogin() // enable form based log in
@@ -35,11 +35,7 @@ import org.springframework.security.config.annotation.authentication.configurati
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import static org.springframework.security.config.Customizer.withDefaults;
@@ -64,11 +60,6 @@ class HttpSecurityConfiguration {
private ApplicationContext context;
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private ContentNegotiationStrategy contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
@Autowired
void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
@@ -88,16 +79,6 @@ class HttpSecurityConfiguration {
this.context = context;
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
@Autowired(required = false)
void setContentNegotiationStrategy(ContentNegotiationStrategy contentNegotiationStrategy) {
this.contentNegotiationStrategy = contentNegotiationStrategy;
}
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
@@ -108,12 +89,10 @@ class HttpSecurityConfiguration {
authenticationBuilder.parentAuthenticationManager(authenticationManager());
authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
WebAsyncManagerIntegrationFilter webAsyncManagerIntegrationFilter = new WebAsyncManagerIntegrationFilter();
webAsyncManagerIntegrationFilter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
// @formatter:off
http
.csrf(withDefaults())
.addFilter(webAsyncManagerIntegrationFilter)
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(withDefaults())
.headers(withDefaults())
.sessionManagement(withDefaults())
@@ -152,7 +131,6 @@ class HttpSecurityConfiguration {
private Map<Class<?>, Object> createSharedObjects() {
Map<Class<?>, Object> sharedObjects = new HashMap<>();
sharedObjects.put(ApplicationContext.class, this.context);
sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy);
return sharedObjects;
}
@@ -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.
@@ -23,7 +23,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
@@ -76,18 +75,11 @@ final class OAuth2ClientConfiguration {
private OAuth2AuthorizedClientManager authorizedClientManager;
private SecurityContextHolderStrategy securityContextHolderStrategy;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
OAuth2AuthorizedClientManager authorizedClientManager = getAuthorizedClientManager();
if (authorizedClientManager != null) {
OAuth2AuthorizedClientArgumentResolver resolver = new OAuth2AuthorizedClientArgumentResolver(
authorizedClientManager);
if (this.securityContextHolderStrategy != null) {
resolver.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
}
argumentResolvers.add(resolver);
argumentResolvers.add(new OAuth2AuthorizedClientArgumentResolver(authorizedClientManager));
}
}
@@ -118,11 +110,6 @@ final class OAuth2ClientConfiguration {
}
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
this.securityContextHolderStrategy = strategy;
}
private OAuth2AuthorizedClientManager getAuthorizedClientManager() {
if (this.authorizedClientManager != null) {
return this.authorizedClientManager;
@@ -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.
@@ -37,13 +37,10 @@ import reactor.util.context.Context;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@@ -65,37 +62,24 @@ import org.springframework.web.context.request.ServletRequestAttributes;
@Configuration(proxyBeanMethods = false)
class SecurityReactorContextConfiguration {
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
@Bean
SecurityReactorContextSubscriberRegistrar securityReactorContextSubscriberRegistrar() {
SecurityReactorContextSubscriberRegistrar registrar = new SecurityReactorContextSubscriberRegistrar();
registrar.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
return registrar;
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
return new SecurityReactorContextSubscriberRegistrar();
}
static class SecurityReactorContextSubscriberRegistrar implements InitializingBean, DisposableBean {
private static final String SECURITY_REACTOR_CONTEXT_OPERATOR_KEY = "org.springframework.security.SECURITY_REACTOR_CONTEXT_OPERATOR";
private final Map<Object, Supplier<Object>> CONTEXT_ATTRIBUTE_VALUE_LOADERS = new HashMap<>();
private static final Map<Object, Supplier<Object>> CONTEXT_ATTRIBUTE_VALUE_LOADERS = new HashMap<>();
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
SecurityReactorContextSubscriberRegistrar() {
this.CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletRequest.class,
static {
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletRequest.class,
SecurityReactorContextSubscriberRegistrar::getRequest);
this.CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletResponse.class,
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletResponse.class,
SecurityReactorContextSubscriberRegistrar::getResponse);
this.CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(Authentication.class, this::getAuthentication);
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(Authentication.class,
SecurityReactorContextSubscriberRegistrar::getAuthentication);
}
@Override
@@ -110,11 +94,6 @@ class SecurityReactorContextConfiguration {
Hooks.resetOnLastOperator(SECURITY_REACTOR_CONTEXT_OPERATOR_KEY);
}
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
<T> CoreSubscriber<T> createSubscriberIfNecessary(CoreSubscriber<T> delegate) {
if (delegate.currentContext().hasKey(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES)) {
// Already enriched. No need to create Subscriber so return original
@@ -123,8 +102,8 @@ class SecurityReactorContextConfiguration {
return new SecurityReactorContextSubscriber<>(delegate, getContextAttributes());
}
private Map<Object, Object> getContextAttributes() {
return new LoadingMap<>(this.CONTEXT_ATTRIBUTE_VALUE_LOADERS);
private static Map<Object, Object> getContextAttributes() {
return new LoadingMap<>(CONTEXT_ATTRIBUTE_VALUE_LOADERS);
}
private static HttpServletRequest getRequest() {
@@ -145,8 +124,8 @@ class SecurityReactorContextConfiguration {
return null;
}
private Authentication getAuthentication() {
return this.securityContextHolderStrategy.getContext().getAuthentication();
private static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +24,6 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.BeanResolver;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.web.method.annotation.CsrfTokenArgumentResolver;
import org.springframework.security.web.method.annotation.CurrentSecurityContextArgumentResolver;
@@ -52,21 +50,16 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
private BeanResolver beanResolver;
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
@Override
@SuppressWarnings("deprecation")
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
AuthenticationPrincipalArgumentResolver authenticationPrincipalResolver = new AuthenticationPrincipalArgumentResolver();
authenticationPrincipalResolver.setBeanResolver(this.beanResolver);
authenticationPrincipalResolver.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
argumentResolvers.add(authenticationPrincipalResolver);
argumentResolvers
.add(new org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver());
CurrentSecurityContextArgumentResolver currentSecurityContextArgumentResolver = new CurrentSecurityContextArgumentResolver();
currentSecurityContextArgumentResolver.setBeanResolver(this.beanResolver);
currentSecurityContextArgumentResolver.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
argumentResolvers.add(currentSecurityContextArgumentResolver);
argumentResolvers.add(new CsrfTokenArgumentResolver());
}
@@ -79,9 +72,6 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.beanResolver = new BeanFactoryResolver(applicationContext.getAutowireCapableBeanFactory());
if (applicationContext.getBeanNamesForType(SecurityContextHolderStrategy.class).length == 1) {
this.securityContextHolderStrategy = applicationContext.getBean(SecurityContextHolderStrategy.class);
}
}
}
@@ -299,7 +299,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
.getSecurityContextRepository();
this.authFilter.setSecurityContextRepository(securityContextRepository);
}
this.authFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
F filter = postProcess(this.authFilter);
http.addFilter(filter);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -16,14 +16,11 @@
package org.springframework.security.config.annotation.web.configurers;
import org.springframework.context.ApplicationContext;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.DefaultSecurityFilterChain;
/**
@@ -35,8 +32,6 @@ import org.springframework.security.web.DefaultSecurityFilterChain;
public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T, B>, B extends HttpSecurityBuilder<B>>
extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {
private SecurityContextHolderStrategy securityContextHolderStrategy;
/**
* Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh
* version of the configuration can be applied.
@@ -54,19 +49,4 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
return (T) this;
}
protected SecurityContextHolderStrategy getSecurityContextHolderStrategy() {
if (this.securityContextHolderStrategy != null) {
return this.securityContextHolderStrategy;
}
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
String[] names = context.getBeanNamesForType(SecurityContextHolderStrategy.class);
if (names.length == 1) {
this.securityContextHolderStrategy = context.getBean(SecurityContextHolderStrategy.class);
}
else {
this.securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();
}
return this.securityContextHolderStrategy;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -60,9 +60,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
* @since 3.2
* @see ExpressionUrlAuthorizationConfigurer
* @see UrlAuthorizationConfigurer
* @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead
*/
@Deprecated
public abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>, H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<C, H> {
@@ -146,7 +144,6 @@ public abstract class AbstractInterceptUrlConfigurer<C extends AbstractIntercept
securityInterceptor.setSecurityMetadataSource(metadataSource);
securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http));
securityInterceptor.setAuthenticationManager(authenticationManager);
securityInterceptor.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
securityInterceptor.afterPropertiesSet();
return securityInterceptor;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -146,9 +146,7 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
}
if (this.authenticationFilter == null) {
this.authenticationFilter = new AnonymousAuthenticationFilter(getKey(), this.principal, this.authorities);
this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
}
this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
this.authenticationProvider = postProcess(this.authenticationProvider);
http.authenticationProvider(this.authenticationProvider);
}
@@ -86,7 +86,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
authorizationFilter.setAuthorizationEventPublisher(this.publisher);
authorizationFilter.setShouldFilterAllDispatcherTypes(this.registry.shouldFilterAllDispatcherTypes);
authorizationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
http.addFilter(postProcess(authorizationFilter));
}
@@ -146,20 +145,12 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
return postProcess(this.managerBuilder.build());
}
/**
* @deprecated use {@link #requestMatchers(String...)} instead
*/
@Override
@Deprecated
public MvcMatchersAuthorizedUrl mvcMatchers(String... mvcPatterns) {
return mvcMatchers(null, mvcPatterns);
}
/**
* @deprecated use {@link #requestMatchers(HttpMethod, String...)} instead
*/
@Override
@Deprecated
public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) {
return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns));
}
@@ -211,9 +202,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* configuring the {@link MvcRequestMatcher#setServletPath(String)}.
*
* @author Evgeniy Cheban
* @deprecated use {@link MvcRequestMatcher.Builder} instead
*/
@Deprecated
public final class MvcMatchersAuthorizedUrl extends AuthorizedUrl {
private MvcMatchersAuthorizedUrl(List<MvcRequestMatcher> matchers) {
@@ -328,39 +317,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
return access(AuthenticatedAuthorizationManager.authenticated());
}
/**
* Specify that URLs are allowed by users who have authenticated and were not
* "remembered".
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
* customization
* @since 5.8
* @see RememberMeConfigurer
*/
public AuthorizationManagerRequestMatcherRegistry fullyAuthenticated() {
return access(AuthenticatedAuthorizationManager.fullyAuthenticated());
}
/**
* Specify that URLs are allowed by users that have been remembered.
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
* customization
* @since 5.8
* @see RememberMeConfigurer
*/
public AuthorizationManagerRequestMatcherRegistry rememberMe() {
return access(AuthenticatedAuthorizationManager.rememberMe());
}
/**
* Specify that URLs are allowed by anonymous users.
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
* customization
* @since 5.8
*/
public AuthorizationManagerRequestMatcherRegistry anonymous() {
return access(AuthenticatedAuthorizationManager.anonymous());
}
/**
* Allows specifying a custom {@link AuthorizationManager}.
* @param manager the {@link AuthorizationManager} to use
@@ -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.
@@ -155,21 +155,13 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
setApplicationContext(context);
}
/**
* @deprecated use {@link #requestMatchers(HttpMethod, String...)} instead
*/
@Override
@Deprecated
public MvcMatchersRequiresChannelUrl mvcMatchers(HttpMethod method, String... mvcPatterns) {
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
return new MvcMatchersRequiresChannelUrl(mvcMatchers);
}
/**
* @deprecated use {@link #requestMatchers(String...)} instead
*/
@Override
@Deprecated
public MvcMatchersRequiresChannelUrl mvcMatchers(String... patterns) {
return mvcMatchers(null, patterns);
}
@@ -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.
@@ -36,7 +36,6 @@ import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfLogoutHandler;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.csrf.LazyCsrfTokenRepository;
import org.springframework.security.web.csrf.MissingCsrfTokenException;
@@ -90,8 +89,6 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private CsrfTokenRequestHandler requestHandler;
private final ApplicationContext context;
/**
@@ -127,18 +124,6 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
return this;
}
/**
* Specify a {@link CsrfTokenRequestHandler} to use for making the {@code CsrfToken}
* available as a request attribute.
* @param requestHandler the {@link CsrfTokenRequestHandler} to use
* @return the {@link CsrfConfigurer} for further customizations
* @since 5.8
*/
public CsrfConfigurer<H> csrfTokenRequestHandler(CsrfTokenRequestHandler requestHandler) {
this.requestHandler = requestHandler;
return this;
}
/**
* <p>
* Allows specifying {@link HttpServletRequest} that should not use CSRF Protection
@@ -162,10 +147,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* </pre>
*
* @since 4.0
* @deprecated use {@link #ignoringRequestMatchers(RequestMatcher...)} with an
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} instead
*/
@Deprecated
public CsrfConfigurer<H> ignoringAntMatchers(String... antPatterns) {
return new IgnoreCsrfProtectionRegistry(this.context).antMatchers(antPatterns).and();
}
@@ -199,35 +181,6 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers).and();
}
/**
* <p>
* Allows specifying {@link HttpServletRequest} that should not use CSRF Protection
* even if they match the {@link #requireCsrfProtectionMatcher(RequestMatcher)}.
* </p>
*
* <p>
* For example, the following configuration will ensure CSRF protection ignores:
* </p>
* <ul>
* <li>Any GET, HEAD, TRACE, OPTIONS (this is the default)</li>
* <li>We also explicitly state to ignore any request that starts with "/sockjs/"</li>
* </ul>
*
* <pre>
* http
* .csrf()
* .ignoringRequestMatchers("/sockjs/**")
* .and()
* ...
* </pre>
*
* @since 5.8
* @see AbstractRequestMatcherRegistry#requestMatchers(String...)
*/
public CsrfConfigurer<H> ignoringRequestMatchers(String... patterns) {
return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(patterns).and();
}
/**
* <p>
* Specify the {@link SessionAuthenticationStrategy} to use. The default is a
@@ -265,9 +218,6 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
if (sessionConfigurer != null) {
sessionConfigurer.addSessionAuthenticationStrategy(getSessionAuthenticationStrategy());
}
if (this.requestHandler != null) {
filter.setRequestHandler(this.requestHandler);
}
filter = postProcess(filter);
http.addFilter(filter);
}
@@ -356,12 +306,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
if (this.sessionAuthenticationStrategy != null) {
return this.sessionAuthenticationStrategy;
}
CsrfAuthenticationStrategy csrfAuthenticationStrategy = new CsrfAuthenticationStrategy(
this.csrfTokenRepository);
if (this.requestHandler != null) {
csrfAuthenticationStrategy.setRequestHandler(this.requestHandler);
}
return csrfAuthenticationStrategy;
return new CsrfAuthenticationStrategy(this.csrfTokenRepository);
}
/**
@@ -378,22 +323,14 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
setApplicationContext(context);
}
/**
* @deprecated use {@link #requestMatchers(HttpMethod, String...)} instead
*/
@Override
@Deprecated
public MvcMatchersIgnoreCsrfProtectionRegistry mvcMatchers(HttpMethod method, String... mvcPatterns) {
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
CsrfConfigurer.this.ignoredCsrfProtectionMatchers.addAll(mvcMatchers);
return new MvcMatchersIgnoreCsrfProtectionRegistry(getApplicationContext(), mvcMatchers);
}
/**
* @deprecated use {@link #requestMatchers(String...)} instead
*/
@Override
@Deprecated
public MvcMatchersIgnoreCsrfProtectionRegistry mvcMatchers(String... mvcPatterns) {
return mvcMatchers(null, mvcPatterns);
}
@@ -50,7 +50,8 @@ import org.springframework.security.web.csrf.CsrfToken;
*
* <h2>Shared Objects Created</h2>
*
* No shared objects are created. isLogoutRequest
* No shared objects are created.
*
* <h2>Shared Objects Used</h2>
*
* The following shared objects are used:
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2018 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.
@@ -187,7 +187,6 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
getRequestCache(http));
AccessDeniedHandler deniedHandler = getAccessDeniedHandler(http);
exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);
exceptionTranslationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
http.addFilter(exceptionTranslationFilter);
}
@@ -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.
@@ -79,9 +79,7 @@ import org.springframework.util.StringUtils;
* @author Yanming Zhou
* @since 3.2
* @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()
* @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead
*/
@Deprecated
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> {
@@ -222,20 +220,12 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
setApplicationContext(context);
}
/**
* @deprecated use {@link #requestMatchers(HttpMethod, String...)} instead
*/
@Override
@Deprecated
public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) {
return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns));
}
/**
* @deprecated use {@link #requestMatchers(String...)} instead
*/
@Override
@Deprecated
public MvcMatchersAuthorizedUrl mvcMatchers(String... patterns) {
return mvcMatchers(null, patterns);
}
@@ -266,11 +266,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
* @return the {@link HpkpConfig} for additional customizations
*
* @since 4.1
* @deprecated see <a href=
* "https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning">Certificate
* and Public Key Pinning</a> for more context
*/
@Deprecated
public HpkpConfig httpPublicKeyPinning() {
return this.hpkp.enable();
}
@@ -281,11 +277,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
* @param hpkpCustomizer the {@link Customizer} to provide more options for the
* {@link HpkpConfig}
* @return the {@link HeadersConfigurer} for additional customizations
* @deprecated see <a href=
* "https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning">Certificate
* and Public Key Pinning</a> for more context
*/
@Deprecated
public HeadersConfigurer<H> httpPublicKeyPinning(Customizer<HpkpConfig> hpkpCustomizer) {
hpkpCustomizer.customize(this.hpkp.enable());
return HeadersConfigurer.this;
@@ -737,10 +729,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
* If false, will not specify the mode as blocked. In this instance, any content
* will be attempted to be fixed. If true, the content will be replaced with "#".
* @param enabled the new value
* @deprecated use
* {@link XXssConfig#headerValue(XXssProtectionHeaderWriter.HeaderValue)} instead
*/
@Deprecated
public XXssConfig block(boolean enabled) {
this.writer.setBlock(enabled);
return this;
@@ -768,49 +757,12 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
* X-XSS-Protection: 0
* </pre>
* @param enabled the new value
* @deprecated use
* {@link XXssConfig#headerValue(XXssProtectionHeaderWriter.HeaderValue)} instead
*/
@Deprecated
public XXssConfig xssProtectionEnabled(boolean enabled) {
this.writer.setEnabled(enabled);
return this;
}
/**
* Sets the value of the X-XSS-PROTECTION header. OWASP recommends using
* {@link XXssProtectionHeaderWriter.HeaderValue#DISABLED}.
*
* If {@link XXssProtectionHeaderWriter.HeaderValue#DISABLED}, will specify that
* X-XSS-Protection is disabled. For example:
*
* <pre>
* X-XSS-Protection: 0
* </pre>
*
* If {@link XXssProtectionHeaderWriter.HeaderValue#ENABLED}, will contain a value
* of 1, but will not specify the mode as blocked. In this instance, any content
* will be attempted to be fixed. For example:
*
* <pre>
* X-XSS-Protection: 1
* </pre>
*
* If {@link XXssProtectionHeaderWriter.HeaderValue#ENABLED_MODE_BLOCK}, will
* contain a value of 1 and will specify mode as blocked. The content will be
* replaced with "#". For example:
*
* <pre>
* X-XSS-Protection: 1 ; mode=block
* </pre>
* @param headerValue the new header value
* @since 5.8
*/
public XXssConfig headerValue(XXssProtectionHeaderWriter.HeaderValue headerValue) {
this.writer.setHeaderValue(headerValue);
return this;
}
/**
* Disables X-XSS-Protection header (does not include it)
* @return the {@link HeadersConfigurer} for additional configuration
@@ -1048,12 +1000,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
}
/**
* @deprecated see <a href=
* "https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning">Certificate
* and Public Key Pinning</a> for more context
*/
@Deprecated
public final class HpkpConfig {
private HpkpHeaderWriter writer;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -199,7 +199,6 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
if (rememberMeServices != null) {
basicAuthenticationFilter.setRememberMeServices(rememberMeServices);
}
basicAuthenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
basicAuthenticationFilter = postProcess(basicAuthenticationFilter);
http.addFilter(basicAuthenticationFilter);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@@ -198,8 +198,7 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends Abstr
@Override
public void configure(H http) {
J2eePreAuthenticatedProcessingFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class),
http);
J2eePreAuthenticatedProcessingFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class));
http.addFilter(filter);
}
@@ -209,14 +208,12 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends Abstr
* @param authenticationManager the {@link AuthenticationManager} to use.
* @return the {@link J2eePreAuthenticatedProcessingFilter} to use.
*/
private J2eePreAuthenticatedProcessingFilter getFilter(AuthenticationManager authenticationManager, H http) {
private J2eePreAuthenticatedProcessingFilter getFilter(AuthenticationManager authenticationManager) {
if (this.j2eePreAuthenticatedProcessingFilter == null) {
this.j2eePreAuthenticatedProcessingFilter = new J2eePreAuthenticatedProcessingFilter();
this.j2eePreAuthenticatedProcessingFilter.setAuthenticationManager(authenticationManager);
this.j2eePreAuthenticatedProcessingFilter
.setAuthenticationDetailsSource(createWebAuthenticationDetailsSource());
this.j2eePreAuthenticatedProcessingFilter
.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
this.j2eePreAuthenticatedProcessingFilter = postProcess(this.j2eePreAuthenticatedProcessingFilter);
}
@@ -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.
@@ -35,6 +35,8 @@ import org.springframework.security.web.authentication.logout.LogoutSuccessHandl
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
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.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -325,18 +327,24 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
* @return the {@link LogoutFilter} to use.
*/
private LogoutFilter createLogoutFilter(H http) {
this.contextLogoutHandler.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
this.contextLogoutHandler.setSecurityContextRepository(getSecurityContextRepository(http));
this.logoutHandlers.add(this.contextLogoutHandler);
this.logoutHandlers.add(postProcess(new LogoutSuccessEventPublishingLogoutHandler()));
LogoutHandler[] handlers = this.logoutHandlers.toArray(new LogoutHandler[0]);
LogoutFilter result = new LogoutFilter(getLogoutSuccessHandler(), handlers);
result.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
result.setLogoutRequestMatcher(getLogoutRequestMatcher(http));
result.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
result = postProcess(result);
return result;
}
private SecurityContextRepository getSecurityContextRepository(H http) {
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
if (securityContextRepository == null) {
securityContextRepository = new HttpSessionSecurityContextRepository();
}
return securityContextRepository;
}
private RequestMatcher getLogoutRequestMatcher(H http) {
if (this.logoutRequestMatcher != null) {
return this.logoutRequestMatcher;
@@ -288,7 +288,6 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
if (this.authenticationSuccessHandler != null) {
rememberMeFilter.setAuthenticationSuccessHandler(this.authenticationSuccessHandler);
}
rememberMeFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
rememberMeFilter = postProcess(rememberMeFilter);
http.addFilter(rememberMeFilter);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2018 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.
@@ -108,13 +108,11 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
if (this.requireExplicitSave) {
SecurityContextHolderFilter securityContextHolderFilter = postProcess(
new SecurityContextHolderFilter(securityContextRepository));
securityContextHolderFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
http.addFilter(securityContextHolderFilter);
}
else {
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
securityContextRepository);
securityContextFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
SessionCreationPolicy sessionCreationPolicy = (sessionManagement != null)
? sessionManagement.getSessionCreationPolicy() : null;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2018 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.
@@ -98,7 +98,6 @@ public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>>
.getBean(grantedAuthorityDefaultsBeanNames[0], GrantedAuthorityDefaults.class);
this.securityContextRequestFilter.setRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
this.securityContextRequestFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
}
this.securityContextRequestFilter = postProcess(this.securityContextRequestFilter);
http.addFilter(this.securityContextRequestFilter);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -135,8 +135,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
private AuthenticationFailureHandler sessionAuthenticationFailureHandler;
private boolean requireExplicitAuthenticationStrategy;
/**
* Creates a new instance
* @see HttpSecurity#sessionManagement()
@@ -157,19 +155,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return this;
}
/**
* Setting this means that explicit invocation of
* {@link SessionAuthenticationStrategy} is required.
* @param requireExplicitAuthenticationStrategy require explicit invocation of
* {@link SessionAuthenticationStrategy}
* @return the {@link SessionManagementConfigurer} for further customization
*/
public SessionManagementConfigurer<H> requireExplicitAuthenticationStrategy(
boolean requireExplicitAuthenticationStrategy) {
this.requireExplicitAuthenticationStrategy = requireExplicitAuthenticationStrategy;
return this;
}
/**
* Setting this attribute will inject the provided invalidSessionStrategy into the
* {@link SessionManagementFilter}. When an invalid session ID is submitted, the
@@ -303,7 +288,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Controls the maximum number of sessions for a user. The default is to allow any
* number of users.
* number of sessions.
* @param maximumSessions the maximum number of sessions for a user
* @return the {@link SessionManagementConfigurer} for further customizations
*/
@@ -366,28 +351,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
@Override
public void configure(H http) {
SessionManagementFilter sessionManagementFilter = createSessionManagementFilter(http);
if (sessionManagementFilter != null) {
http.addFilter(sessionManagementFilter);
}
if (isConcurrentSessionControlEnabled()) {
ConcurrentSessionFilter concurrentSessionFilter = createConcurrencyFilter(http);
concurrentSessionFilter = postProcess(concurrentSessionFilter);
http.addFilter(concurrentSessionFilter);
}
if (!this.enableSessionUrlRewriting) {
http.addFilter(new DisableEncodeUrlFilter());
}
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
http.addFilter(new ForceEagerSessionCreationFilter());
}
}
private SessionManagementFilter createSessionManagementFilter(H http) {
if (this.requireExplicitAuthenticationStrategy) {
return null;
}
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository,
getSessionAuthenticationStrategy(http));
@@ -407,8 +370,20 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
if (trustResolver != null) {
sessionManagementFilter.setTrustResolver(trustResolver);
}
sessionManagementFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
return postProcess(sessionManagementFilter);
sessionManagementFilter = postProcess(sessionManagementFilter);
http.addFilter(sessionManagementFilter);
if (isConcurrentSessionControlEnabled()) {
ConcurrentSessionFilter concurrentSessionFilter = createConcurrencyFilter(http);
concurrentSessionFilter = postProcess(concurrentSessionFilter);
http.addFilter(concurrentSessionFilter);
}
if (!this.enableSessionUrlRewriting) {
http.addFilter(new DisableEncodeUrlFilter());
}
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
http.addFilter(new ForceEagerSessionCreationFilter());
}
}
private ConcurrentSessionFilter createConcurrencyFilter(H http) {
@@ -424,7 +399,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
concurrentSessionFilter.setLogoutHandlers(logoutHandlers);
}
}
concurrentSessionFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
return concurrentSessionFilter;
}
@@ -526,6 +500,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
concurrentSessionControlStrategy.setMaximumSessions(this.maximumSessions);
concurrentSessionControlStrategy.setExceptionIfMaximumExceeded(this.maxSessionsPreventsLogin);
concurrentSessionControlStrategy = postProcess(concurrentSessionControlStrategy);
RegisterSessionAuthenticationStrategy registerSessionStrategy = new RegisterSessionAuthenticationStrategy(
sessionRegistry);
registerSessionStrategy = postProcess(registerSessionStrategy);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2018 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.
@@ -49,10 +49,11 @@ import org.springframework.util.Assert;
* </p>
*
* <pre>
* protected void configure(HttpSecurity http) throws Exception {
* http.apply(new UrlAuthorizationConfigurer&lt;HttpSecurity&gt;()).getRegistry()
* .antMatchers(&quot;/users**&quot;, &quot;/sessions/**&quot;).hasRole(&quot;USER&quot;)
* .antMatchers(&quot;/signup&quot;).hasRole(&quot;ANONYMOUS&quot;).anyRequest().hasRole(&quot;USER&quot;);
* &#64;Bean
* public SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context) throws Exception {
* http.apply(new UrlAuthorizationConfigurer&lt;HttpSecurity&gt;(context)).getRegistry()
* .requestMatchers(&quot;/users**&quot;, &quot;/sessions/**&quot;).hasRole(&quot;USER&quot;)
* .requestMatchers(&quot;/signup&quot;).hasRole(&quot;ANONYMOUS&quot;).anyRequest().hasRole(&quot;USER&quot;);
* }
* </pre>
*
@@ -85,9 +86,7 @@ import org.springframework.util.Assert;
* @author Rob Winch
* @since 3.2
* @see ExpressionUrlAuthorizationConfigurer
* @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead
*/
@Deprecated
public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractInterceptUrlConfigurer<UrlAuthorizationConfigurer<H>, H> {
@@ -202,20 +201,12 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
setApplicationContext(context);
}
/**
* @deprecated use {@link #requestMatchers(HttpMethod, String...)} instead
*/
@Override
@Deprecated
public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) {
return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns));
}
/**
* @deprecated use {@link #requestMatchers(String...)} instead
*/
@Override
@Deprecated
public MvcMatchersAuthorizedUrl mvcMatchers(String... patterns) {
return mvcMatchers(null, patterns);
}
@@ -178,11 +178,11 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
@Override
public void configure(H http) {
X509AuthenticationFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class), http);
X509AuthenticationFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class));
http.addFilter(filter);
}
private X509AuthenticationFilter getFilter(AuthenticationManager authenticationManager, H http) {
private X509AuthenticationFilter getFilter(AuthenticationManager authenticationManager) {
if (this.x509AuthenticationFilter == null) {
this.x509AuthenticationFilter = new X509AuthenticationFilter();
this.x509AuthenticationFilter.setAuthenticationManager(authenticationManager);
@@ -192,7 +192,6 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
if (this.authenticationDetailsSource != null) {
this.x509AuthenticationFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
}
this.x509AuthenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
this.x509AuthenticationFilter = postProcess(this.x509AuthenticationFilter);
}
@@ -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.
@@ -34,7 +34,6 @@ import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequest
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.util.Assert;
@@ -172,8 +171,6 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
private RedirectStrategy authorizationRedirectStrategy;
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
private AuthorizationCodeGrantConfigurer() {
@@ -205,17 +202,6 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
return this;
}
/**
* Sets the redirect strategy for Authorization Endpoint redirect URI.
* @param authorizationRedirectStrategy the redirect strategy
* @return the {@link AuthorizationCodeGrantConfigurer} for further configuration
*/
public AuthorizationCodeGrantConfigurer authorizationRedirectStrategy(
RedirectStrategy authorizationRedirectStrategy) {
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
return this;
}
/**
* Sets the client used for requesting the access token credential from the Token
* Endpoint.
@@ -261,9 +247,6 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
authorizationRequestRedirectFilter
.setAuthorizationRequestRepository(this.authorizationRequestRepository);
}
if (this.authorizationRedirectStrategy != null) {
authorizationRequestRedirectFilter.setAuthorizationRedirectStrategy(this.authorizationRedirectStrategy);
}
RequestCache requestCache = builder.getSharedObject(RequestCache.class);
if (requestCache != null) {
authorizationRequestRedirectFilter.setRequestCache(requestCache);
@@ -289,7 +272,6 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
if (this.authorizationRequestRepository != null) {
authorizationCodeGrantFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
}
authorizationCodeGrantFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
RequestCache requestCache = builder.getSharedObject(RequestCache.class);
if (requestCache != null) {
authorizationCodeGrantFilter.setRequestCache(requestCache);
@@ -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.
@@ -16,7 +16,6 @@
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -68,21 +67,18 @@ import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* An {@link AbstractHttpConfigurer} for OAuth 2.0 Login, which leverages the OAuth 2.0
@@ -294,7 +290,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter(
OAuth2ClientConfigurerUtils.getClientRegistrationRepository(this.getBuilder()),
OAuth2ClientConfigurerUtils.getAuthorizedClientRepository(this.getBuilder()), this.loginProcessingUrl);
authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
this.setAuthenticationFilter(authenticationFilter);
super.loginProcessingUrl(this.loginProcessingUrl);
if (this.loginPage != null) {
@@ -369,10 +364,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
authorizationRequestFilter
.setAuthorizationRequestRepository(this.authorizationEndpointConfig.authorizationRequestRepository);
}
if (this.authorizationEndpointConfig.authorizationRedirectStrategy != null) {
authorizationRequestFilter
.setAuthorizationRedirectStrategy(this.authorizationEndpointConfig.authorizationRedirectStrategy);
}
RequestCache requestCache = http.getSharedObject(RequestCache.class);
if (requestCache != null) {
authorizationRequestFilter.setRequestCache(requestCache);
@@ -512,28 +503,14 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
new OrRequestMatcher(loginPageMatcher, faviconMatcher), defaultEntryPointMatcher);
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
RequestMatcher formLoginNotEnabled = getFormLoginNotEnabledRequestMatcher(http);
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<>();
entryPoints.put(new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher),
formLoginNotEnabled), new LoginUrlAuthenticationEntryPoint(providerLoginPage));
entryPoints.put(new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher)),
new LoginUrlAuthenticationEntryPoint(providerLoginPage));
DelegatingAuthenticationEntryPoint loginEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints);
loginEntryPoint.setDefaultEntryPoint(this.getAuthenticationEntryPoint());
return loginEntryPoint;
}
private RequestMatcher getFormLoginNotEnabledRequestMatcher(B http) {
DefaultLoginPageGeneratingFilter defaultLoginPageGeneratingFilter = http
.getSharedObject(DefaultLoginPageGeneratingFilter.class);
Field formLoginEnabledField = (defaultLoginPageGeneratingFilter != null)
? ReflectionUtils.findField(DefaultLoginPageGeneratingFilter.class, "formLoginEnabled") : null;
if (formLoginEnabledField != null) {
ReflectionUtils.makeAccessible(formLoginEnabledField);
return (request) -> Boolean.FALSE
.equals(ReflectionUtils.getField(formLoginEnabledField, defaultLoginPageGeneratingFilter));
}
return AnyRequestMatcher.INSTANCE;
}
/**
* Configuration options for the Authorization Server's Authorization Endpoint.
*/
@@ -545,8 +522,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
private RedirectStrategy authorizationRedirectStrategy;
private AuthorizationEndpointConfig() {
}
@@ -589,17 +564,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
return this;
}
/**
* Sets the redirect strategy for Authorization Endpoint redirect URI.
* @param authorizationRedirectStrategy the redirect strategy
* @return the {@link AuthorizationEndpointConfig} for further configuration
*/
public AuthorizationEndpointConfig authorizationRedirectStrategy(
RedirectStrategy authorizationRedirectStrategy) {
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
return this;
}
/**
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
* @return the {@link OAuth2LoginConfigurer}
@@ -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.
@@ -46,14 +46,13 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
@@ -108,8 +107,8 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
* </ul>
*
* <p>
* When using {@link #opaqueToken(Customizer)}, supply an introspection endpoint with its
* client credentials and an OpaqueTokenAuthenticationConverter
* When using {@link #opaqueToken(Customizer)}, supply an introspection endpoint and its
* authentication configuration
* </p>
*
* <h2>Security Filters</h2>
@@ -139,7 +138,6 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
*
* @author Josh Cummings
* @author Evgeniy Cheban
* @author Jerome Wacongne &lt;ch4mp@c4-soft.com&gt;
* @since 5.1
* @see BearerTokenAuthenticationFilter
* @see JwtAuthenticationProvider
@@ -272,7 +270,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
filter.setBearerTokenResolver(bearerTokenResolver);
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
filter = postProcess(filter);
http.addFilter(filter);
}
@@ -458,8 +455,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
private Supplier<OpaqueTokenIntrospector> introspector;
private OpaqueTokenAuthenticationConverter authenticationConverter;
OpaqueTokenConfigurer(ApplicationContext context) {
this.context = context;
}
@@ -494,13 +489,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
return this;
}
public OpaqueTokenConfigurer authenticationConverter(
OpaqueTokenAuthenticationConverter authenticationConverter) {
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
this.authenticationConverter = authenticationConverter;
return this;
}
OpaqueTokenIntrospector getIntrospector() {
if (this.introspector != null) {
return this.introspector.get();
@@ -508,28 +496,12 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
return this.context.getBean(OpaqueTokenIntrospector.class);
}
OpaqueTokenAuthenticationConverter getAuthenticationConverter() {
if (this.authenticationConverter != null) {
return this.authenticationConverter;
}
if (this.context.getBeanNamesForType(OpaqueTokenAuthenticationConverter.class).length > 0) {
return this.context.getBean(OpaqueTokenAuthenticationConverter.class);
}
return null;
}
AuthenticationProvider getAuthenticationProvider() {
if (this.authenticationManager != null) {
return null;
}
OpaqueTokenIntrospector introspector = getIntrospector();
OpaqueTokenAuthenticationProvider opaqueTokenAuthenticationProvider = new OpaqueTokenAuthenticationProvider(
introspector);
OpaqueTokenAuthenticationConverter authenticationConverter = getAuthenticationConverter();
if (authenticationConverter != null) {
opaqueTokenAuthenticationProvider.setAuthenticationConverter(authenticationConverter);
}
return opaqueTokenAuthenticationProvider;
return new OpaqueTokenAuthenticationProvider(introspector);
}
AuthenticationManager getAuthenticationManager(H http) {
@@ -32,11 +32,15 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
import org.springframework.security.core.Authentication;
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.OpenSaml4AuthenticationRequestFactory;
import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider;
import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationRequestFactory;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestFactory;
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.servlet.filter.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.DefaultSaml2AuthenticationRequestContextResolver;
import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository;
@@ -44,22 +48,13 @@ import org.springframework.security.saml2.provider.service.web.RelyingPartyRegis
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestContextResolver;
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;
import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@@ -117,8 +112,6 @@ import org.springframework.util.StringUtils;
public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
extends AbstractAuthenticationFilterConfigurer<B, Saml2LoginConfigurer<B>, Saml2WebSsoAuthenticationFilter> {
private static final String OPEN_SAML_4_VERSION = "4";
private String loginPage;
private String authenticationRequestUri = "/saml2/authenticate/{registrationId}";
@@ -239,7 +232,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
relyingPartyRegistrationRepository(http);
this.saml2WebSsoAuthenticationFilter = new Saml2WebSsoAuthenticationFilter(getAuthenticationConverter(http),
this.loginProcessingUrl);
this.saml2WebSsoAuthenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
setAuthenticationRequestRepository(http, this.saml2WebSsoAuthenticationFilter);
setAuthenticationFilter(this.saml2WebSsoAuthenticationFilter);
super.loginProcessingUrl(this.loginProcessingUrl);
@@ -258,7 +250,8 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
this.updateAuthenticationDefaults();
this.updateAccessDefaults(http);
String loginUrl = providerUrlMap.entrySet().iterator().next().getKey();
registerAuthenticationEntryPoint(http, getLoginEntryPoint(http, loginUrl));
final LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint(loginUrl);
registerAuthenticationEntryPoint(http, entryPoint);
}
else {
super.init(http);
@@ -300,22 +293,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
return this.relyingPartyRegistrationRepository;
}
private AuthenticationEntryPoint getLoginEntryPoint(B http, String providerLoginPage) {
RequestMatcher loginPageMatcher = new AntPathRequestMatcher(this.getLoginPage());
RequestMatcher faviconMatcher = new AntPathRequestMatcher("/favicon.ico");
RequestMatcher defaultEntryPointMatcher = this.getAuthenticationEntryPointMatcher(http);
RequestMatcher defaultLoginPageMatcher = new AndRequestMatcher(
new OrRequestMatcher(loginPageMatcher, faviconMatcher), defaultEntryPointMatcher);
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<>();
entryPoints.put(new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher)),
new LoginUrlAuthenticationEntryPoint(providerLoginPage));
DelegatingAuthenticationEntryPoint loginEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints);
loginEntryPoint.setDefaultEntryPoint(this.getAuthenticationEntryPoint());
return loginEntryPoint;
}
private void setAuthenticationRequestRepository(B http,
Saml2WebSsoAuthenticationFilter saml2WebSsoAuthenticationFilter) {
saml2WebSsoAuthenticationFilter.setAuthenticationRequestRepository(getAuthenticationRequestRepository(http));
@@ -343,9 +320,11 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
return resolver;
}
if (version().startsWith("4")) {
return OpenSaml4LoginSupportFactory.getAuthenticationRequestFactory();
return new OpenSaml4AuthenticationRequestFactory();
}
else {
return new OpenSamlAuthenticationRequestFactory();
}
return new OpenSamlAuthenticationRequestFactory();
}
private Saml2AuthenticationRequestContextResolver getAuthenticationRequestContextResolver(B http) {
@@ -375,9 +354,17 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
return authenticationConverterBean;
}
private String version() {
String version = Version.getVersion();
if (version != null) {
return version;
}
return Version.getVersion();
}
private void registerDefaultAuthenticationProvider(B http) {
if (version().startsWith("4")) {
http.authenticationProvider(postProcess(OpenSaml4LoginSupportFactory.getAuthenticationProvider()));
http.authenticationProvider(postProcess(new OpenSaml4AuthenticationProvider()));
}
else {
http.authenticationProvider(postProcess(new OpenSamlAuthenticationProvider()));
@@ -427,19 +414,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
return repository;
}
private String version() {
String version = Version.getVersion();
if (StringUtils.hasText(version)) {
return version;
}
boolean openSaml4ClassPresent = ClassUtils
.isPresent("org.opensaml.core.xml.persist.impl.PassthroughSourceStrategy", null);
if (openSaml4ClassPresent) {
return OPEN_SAML_4_VERSION;
}
throw new IllegalStateException("cannot determine OpenSAML version");
}
private <C> C getSharedOrBean(B http, Class<C> clazz) {
C shared = http.getSharedObject(clazz);
if (shared != null) {
@@ -467,33 +441,4 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
}
}
private static class OpenSaml4LoginSupportFactory {
private static Saml2AuthenticationRequestFactory getAuthenticationRequestFactory() {
try {
Class<?> authenticationRequestFactory = ClassUtils.forName(
"org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationRequestFactory",
OpenSaml4LoginSupportFactory.class.getClassLoader());
return (Saml2AuthenticationRequestFactory) authenticationRequestFactory.getDeclaredConstructor()
.newInstance();
}
catch (ReflectiveOperationException ex) {
throw new IllegalStateException("Could not instantiate OpenSaml4AuthenticationRequestFactory", ex);
}
}
private static AuthenticationProvider getAuthenticationProvider() {
try {
Class<?> authenticationProvider = ClassUtils.forName(
"org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider",
OpenSaml4LoginSupportFactory.class.getClassLoader());
return (AuthenticationProvider) authenticationProvider.getDeclaredConstructor().newInstance();
}
catch (ReflectiveOperationException ex) {
throw new IllegalStateException("Could not instantiate OpenSaml4AuthenticationProvider", ex);
}
}
}
}
@@ -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.
@@ -34,7 +34,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlLogoutRequestValidator;
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlLogoutResponseValidator;
@@ -47,6 +47,8 @@ import org.springframework.security.saml2.provider.service.web.RelyingPartyRegis
import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository;
import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml3LogoutRequestResolver;
import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml3LogoutResponseResolver;
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.Saml2LogoutRequestFilter;
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestRepository;
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestResolver;
@@ -65,8 +67,6 @@ import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Adds SAML 2.0 logout support.
@@ -113,8 +113,6 @@ import org.springframework.util.StringUtils;
public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<Saml2LogoutConfigurer<H>, H> {
private static final String OPEN_SAML_4_VERSION = "4";
private ApplicationContext context;
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
@@ -150,7 +148,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
* <p>
* The Relying Party triggers logout by POSTing to the endpoint. The Asserting Party
* triggers logout based on what is specified by
* {@link RelyingPartyRegistration#getSingleLogoutServiceBindings()}.
* {@link RelyingPartyRegistration#getSingleLogoutServiceBinding()}.
* @param logoutUrl the URL that will invoke logout
* @return the {@link LogoutConfigurer} for further customizations
* @see LogoutConfigurer#logoutUrl(String)
@@ -255,7 +253,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
Saml2LogoutRequestFilter filter = new Saml2LogoutRequestFilter(registrations,
this.logoutRequestConfigurer.logoutRequestValidator(), logoutResponseResolver, logoutHandlers);
filter.setLogoutRequestMatcher(createLogoutRequestMatcher());
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
return postProcess(filter);
}
@@ -272,7 +269,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
LogoutHandler[] logoutHandlers = this.logoutHandlers.toArray(new LogoutHandler[0]);
Saml2RelyingPartyInitiatedLogoutSuccessHandler logoutRequestSuccessHandler = createSaml2LogoutRequestSuccessHandler(
registrations);
logoutRequestSuccessHandler.setLogoutRequestRepository(this.logoutRequestConfigurer.logoutRequestRepository);
LogoutFilter logoutFilter = new LogoutFilter(logoutRequestSuccessHandler, logoutHandlers);
logoutFilter.setLogoutRequestMatcher(createLogoutMatcher());
return postProcess(logoutFilter);
@@ -280,7 +276,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
private RequestMatcher createLogoutMatcher() {
RequestMatcher logout = new AntPathRequestMatcher(this.logoutUrl, "POST");
RequestMatcher saml2 = new Saml2RequestMatcher(getSecurityContextHolderStrategy());
RequestMatcher saml2 = new Saml2RequestMatcher();
return new AndRequestMatcher(logout, saml2);
}
@@ -308,19 +304,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
return this.logoutResponseConfigurer.logoutResponseResolver(relyingPartyRegistrationResolver);
}
private String version() {
String version = Version.getVersion();
if (StringUtils.hasText(version)) {
return version;
}
boolean openSaml4ClassPresent = ClassUtils
.isPresent("org.opensaml.core.xml.persist.impl.PassthroughSourceStrategy", null);
if (openSaml4ClassPresent) {
return OPEN_SAML_4_VERSION;
}
throw new IllegalStateException("cannot determine OpenSAML version");
}
private <C> C getBeanOrNull(Class<C> clazz) {
if (this.context == null) {
return null;
@@ -331,6 +314,14 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
return this.context.getBean(clazz);
}
private String version() {
String version = Version.getVersion();
if (version != null) {
return version;
}
return Version.getVersion();
}
/**
* A configurer for SAML 2.0 LogoutRequest components
*/
@@ -352,7 +343,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
*
* <p>
* The Asserting Party should use whatever HTTP method specified in
* {@link RelyingPartyRegistration#getSingleLogoutServiceBindings()}.
* {@link RelyingPartyRegistration#getSingleLogoutServiceBinding()}.
* @param logoutUrl the URL that will receive the SAML 2.0 Logout Request
* @return the {@link LogoutRequestConfigurer} for further customizations
* @see Saml2LogoutConfigurer#logoutUrl(String)
@@ -411,7 +402,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
return this.logoutRequestResolver;
}
if (version().startsWith("4")) {
return OpenSaml4LogoutSupportFactory.getLogoutRequestResolver(relyingPartyRegistrationResolver);
return new OpenSaml4LogoutRequestResolver(relyingPartyRegistrationResolver);
}
return new OpenSaml3LogoutRequestResolver(relyingPartyRegistrationResolver);
}
@@ -434,7 +425,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
*
* <p>
* The Asserting Party should use whatever HTTP method specified in
* {@link RelyingPartyRegistration#getSingleLogoutServiceBindings()}.
* {@link RelyingPartyRegistration#getSingleLogoutServiceBinding()}.
* @param logoutUrl the URL that will receive the SAML 2.0 Logout Response
* @return the {@link LogoutResponseConfigurer} for further customizations
* @see Saml2LogoutConfigurer#logoutUrl(String)
@@ -479,28 +470,22 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
private Saml2LogoutResponseResolver logoutResponseResolver(
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
if (this.logoutResponseResolver != null) {
return this.logoutResponseResolver;
if (this.logoutResponseResolver == null) {
if (version().startsWith("4")) {
return new OpenSaml4LogoutResponseResolver(relyingPartyRegistrationResolver);
}
return new OpenSaml3LogoutResponseResolver(relyingPartyRegistrationResolver);
}
if (version().startsWith("4")) {
return OpenSaml4LogoutSupportFactory.getLogoutResponseResolver(relyingPartyRegistrationResolver);
}
return new OpenSaml3LogoutResponseResolver(relyingPartyRegistrationResolver);
return this.logoutResponseResolver;
}
}
private static class Saml2RequestMatcher implements RequestMatcher {
private final SecurityContextHolderStrategy securityContextHolderStrategy;
Saml2RequestMatcher(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
@Override
public boolean matches(HttpServletRequest request) {
Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return false;
}
@@ -534,38 +519,4 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
}
private static class OpenSaml4LogoutSupportFactory {
private static Saml2LogoutResponseResolver getLogoutResponseResolver(
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
try {
Class<?> logoutResponseResolver = ClassUtils.forName(
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver",
OpenSaml4LogoutSupportFactory.class.getClassLoader());
return (Saml2LogoutResponseResolver) logoutResponseResolver
.getDeclaredConstructor(RelyingPartyRegistrationResolver.class)
.newInstance(relyingPartyRegistrationResolver);
}
catch (ReflectiveOperationException ex) {
throw new IllegalStateException("Could not instantiate OpenSaml4LogoutResponseResolver", ex);
}
}
private static Saml2LogoutRequestResolver getLogoutRequestResolver(
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
try {
Class<?> logoutRequestResolver = ClassUtils.forName(
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutRequestResolver",
OpenSaml4LogoutSupportFactory.class.getClassLoader());
return (Saml2LogoutRequestResolver) logoutRequestResolver
.getDeclaredConstructor(RelyingPartyRegistrationResolver.class)
.newInstance(relyingPartyRegistrationResolver);
}
catch (ReflectiveOperationException ex) {
throw new IllegalStateException("Could not instantiate OpenSaml4LogoutRequestResolver", ex);
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,6 @@ import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
import org.springframework.security.messaging.util.matcher.MessageMatcher;
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
@@ -44,9 +43,7 @@ import org.springframework.util.StringUtils;
*
* @author Rob Winch
* @since 4.0
* @deprecated Use {@link MessageMatcherDelegatingAuthorizationManager} instead
*/
@Deprecated
public class MessageSecurityMetadataSourceRegistry {
private static final String permitAll = "permitAll";
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,12 +81,9 @@ import org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsSe
*
* @author Rob Winch
* @since 4.0
* @see WebSocketMessageBrokerSecurityConfiguration
* @deprecated Use {@link EnableWebSocketSecurity} instead
*/
@Order(Ordered.HIGHEST_PRECEDENCE + 100)
@Import(ObjectPostProcessorConfiguration.class)
@Deprecated
public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends AbstractWebSocketMessageBrokerConfigurer
implements SmartInitializingSingleton {
@@ -1,58 +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.socket;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* Allows configuring WebSocket Authorization.
*
* <p>
* For example:
* </p>
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSocketSecurity
* public class WebSocketSecurityConfig {
*
* &#064;Bean
* AuthorizationManager&lt;Message&lt;?&gt;&gt; authorizationManager(MessageMatcherDelegatingAuthorizationManager.Builder messages) {
* messages.simpDestMatchers(&quot;/user/queue/errors&quot;).permitAll()
* .simpDestMatchers(&quot;/admin/**&quot;).hasRole(&quot;ADMIN&quot;)
* .anyMessage().authenticated();
* return messages.build();
* }
* }
* </pre>
*
* @author Josh Cummings
* @since 5.8
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(WebSocketMessageBrokerSecurityConfiguration.class)
public @interface EnableWebSocketSecurity {
}
@@ -1,38 +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.socket;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
import org.springframework.util.AntPathMatcher;
final class MessageMatcherAuthorizationManagerConfiguration {
@Bean
@Scope("prototype")
MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder(
ApplicationContext context) {
return MessageMatcherDelegatingAuthorizationManager.builder().simpDestPathMatcher(
() -> (context.getBeanNamesForType(SimpAnnotationMethodMessageHandler.class).length > 0)
? context.getBean(SimpAnnotationMethodMessageHandler.class).getPathMatcher()
: new AntPathMatcher());
}
}
@@ -1,160 +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.socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor;
import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.messaging.context.SecurityContextChannelInterceptor;
import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor;
import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
import org.springframework.util.Assert;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
import org.springframework.web.socket.sockjs.SockJsService;
import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler;
import org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService;
@Order(Ordered.HIGHEST_PRECEDENCE + 100)
@Import(MessageMatcherAuthorizationManagerConfiguration.class)
final class WebSocketMessageBrokerSecurityConfiguration
implements WebSocketMessageBrokerConfigurer, SmartInitializingSingleton {
private static final String SIMPLE_URL_HANDLER_MAPPING_BEAN_NAME = "stompWebSocketHandlerMapping";
private MessageMatcherDelegatingAuthorizationManager b;
private static final AuthorizationManager<Message<?>> ANY_MESSAGE_AUTHENTICATED = MessageMatcherDelegatingAuthorizationManager
.builder().anyMessage().authenticated().build();
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private final SecurityContextChannelInterceptor securityContextChannelInterceptor = new SecurityContextChannelInterceptor();
private final ChannelInterceptor csrfChannelInterceptor = new CsrfChannelInterceptor();
private AuthorizationChannelInterceptor authorizationChannelInterceptor = new AuthorizationChannelInterceptor(
ANY_MESSAGE_AUTHENTICATED);
private ApplicationContext context;
WebSocketMessageBrokerSecurityConfiguration(ApplicationContext context) {
this.context = context;
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
AuthenticationPrincipalArgumentResolver resolver = new AuthenticationPrincipalArgumentResolver();
resolver.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
argumentResolvers.add(resolver);
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
this.authorizationChannelInterceptor
.setAuthorizationEventPublisher(new SpringAuthorizationEventPublisher(this.context));
this.authorizationChannelInterceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
this.securityContextChannelInterceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
registration.interceptors(this.securityContextChannelInterceptor, this.csrfChannelInterceptor,
this.authorizationChannelInterceptor);
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
@Autowired(required = false)
void setAuthorizationManager(AuthorizationManager<Message<?>> authorizationManager) {
this.authorizationChannelInterceptor = new AuthorizationChannelInterceptor(authorizationManager);
}
@Override
public void afterSingletonsInstantiated() {
SimpleUrlHandlerMapping mapping = getBeanOrNull(SIMPLE_URL_HANDLER_MAPPING_BEAN_NAME,
SimpleUrlHandlerMapping.class);
if (mapping == null) {
return;
}
configureCsrf(mapping);
}
private <T> T getBeanOrNull(String name, Class<T> type) {
Map<String, T> beans = this.context.getBeansOfType(type);
return beans.get(name);
}
private void configureCsrf(SimpleUrlHandlerMapping mapping) {
Map<String, Object> mappings = mapping.getHandlerMap();
for (Object object : mappings.values()) {
if (object instanceof SockJsHttpRequestHandler) {
setHandshakeInterceptors((SockJsHttpRequestHandler) object);
}
else if (object instanceof WebSocketHttpRequestHandler) {
setHandshakeInterceptors((WebSocketHttpRequestHandler) object);
}
else {
throw new IllegalStateException(
"Bean " + SIMPLE_URL_HANDLER_MAPPING_BEAN_NAME + " is expected to contain mappings to either a "
+ "SockJsHttpRequestHandler or a WebSocketHttpRequestHandler but got " + object);
}
}
}
private void setHandshakeInterceptors(SockJsHttpRequestHandler handler) {
SockJsService sockJsService = handler.getSockJsService();
Assert.state(sockJsService instanceof TransportHandlingSockJsService,
() -> "sockJsService must be instance of TransportHandlingSockJsService got " + sockJsService);
TransportHandlingSockJsService transportHandlingSockJsService = (TransportHandlingSockJsService) sockJsService;
List<HandshakeInterceptor> handshakeInterceptors = transportHandlingSockJsService.getHandshakeInterceptors();
List<HandshakeInterceptor> interceptorsToSet = new ArrayList<>(handshakeInterceptors.size() + 1);
interceptorsToSet.add(new CsrfTokenHandshakeInterceptor());
interceptorsToSet.addAll(handshakeInterceptors);
transportHandlingSockJsService.setHandshakeInterceptors(interceptorsToSet);
}
private void setHandshakeInterceptors(WebSocketHttpRequestHandler handler) {
List<HandshakeInterceptor> handshakeInterceptors = handler.getHandshakeInterceptors();
List<HandshakeInterceptor> interceptorsToSet = new ArrayList<>(handshakeInterceptors.size() + 1);
interceptorsToSet.add(new CsrfTokenHandshakeInterceptor());
interceptorsToSet.addAll(handshakeInterceptors);
handler.setHandshakeInterceptors(interceptorsToSet);
}
}
@@ -236,7 +236,6 @@ final class AuthenticationConfigBuilder {
AuthenticationConfigBuilder(Element element, boolean forceAutoConfig, ParserContext pc,
SessionCreationPolicy sessionPolicy, BeanReference requestCache, BeanReference authenticationManager,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef,
BeanReference authenticationFilterSecurityContextRepositoryRef, BeanReference sessionStrategy,
BeanReference portMapper, BeanReference portResolver, BeanMetadataElement csrfLogoutHandler) {
this.httpElt = element;
@@ -248,29 +247,26 @@ final class AuthenticationConfigBuilder {
this.portMapper = portMapper;
this.portResolver = portResolver;
this.csrfLogoutHandler = csrfLogoutHandler;
createAnonymousFilter(authenticationFilterSecurityContextHolderStrategyRef);
createRememberMeFilter(authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
createBasicFilter(authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
createBearerTokenAuthenticationFilter(authenticationManager,
authenticationFilterSecurityContextHolderStrategyRef);
createFormLoginFilter(sessionStrategy, authenticationManager,
authenticationFilterSecurityContextHolderStrategyRef, authenticationFilterSecurityContextRepositoryRef);
createAnonymousFilter();
createRememberMeFilter(authenticationManager);
createBasicFilter(authenticationManager);
createBearerTokenAuthenticationFilter(authenticationManager);
createFormLoginFilter(sessionStrategy, authenticationManager, authenticationFilterSecurityContextRepositoryRef);
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager,
authenticationFilterSecurityContextRepositoryRef, authenticationFilterSecurityContextHolderStrategyRef);
authenticationFilterSecurityContextRepositoryRef);
createOpenIDLoginFilter(sessionStrategy, authenticationManager,
authenticationFilterSecurityContextRepositoryRef);
createSaml2LoginFilter(authenticationManager, authenticationFilterSecurityContextRepositoryRef);
createX509Filter(authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
createJeeFilter(authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
createLogoutFilter(authenticationFilterSecurityContextHolderStrategyRef);
createSaml2LogoutFilter(authenticationFilterSecurityContextHolderStrategyRef);
createX509Filter(authenticationManager);
createJeeFilter(authenticationManager);
createLogoutFilter();
createSaml2LogoutFilter();
createLoginPageFilterIfNeeded();
createUserDetailsServiceFactory();
createExceptionTranslationFilter(authenticationFilterSecurityContextHolderStrategyRef);
createExceptionTranslationFilter();
}
void createRememberMeFilter(BeanReference authenticationManager,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
void createRememberMeFilter(BeanReference authenticationManager) {
// Parse remember me before logout as RememberMeServices is also a LogoutHandler
// implementation.
Element rememberMeElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.REMEMBER_ME);
@@ -280,7 +276,7 @@ final class AuthenticationConfigBuilder {
key = createKey();
}
RememberMeBeanDefinitionParser rememberMeParser = new RememberMeBeanDefinitionParser(key,
authenticationManager, authenticationFilterSecurityContextHolderStrategyRef);
authenticationManager);
this.rememberMeFilter = rememberMeParser.parse(rememberMeElt, this.pc);
this.rememberMeServicesId = rememberMeParser.getRememberMeServicesId();
createRememberMeProvider(key);
@@ -297,7 +293,6 @@ final class AuthenticationConfigBuilder {
}
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef,
BeanReference authenticationFilterSecurityContextRepositoryRef) {
Element formLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.FORM_LOGIN);
RootBeanDefinition formFilter = null;
@@ -318,8 +313,6 @@ final class AuthenticationConfigBuilder {
formFilter.getPropertyValues().addPropertyValue("securityContextRepository",
authenticationFilterSecurityContextRepositoryRef);
}
formFilter.getPropertyValues().addPropertyValue("securityContextHolderStrategy",
authenticationFilterSecurityContextHolderStrategyRef);
// Id is required by login page filter
this.formFilterId = this.pc.getReaderContext().generateBeanName(formFilter);
this.pc.registerBeanComponent(new BeanComponentDefinition(formFilter, this.formFilterId));
@@ -328,26 +321,22 @@ final class AuthenticationConfigBuilder {
}
void createOAuth2ClientFilters(BeanReference sessionStrategy, BeanReference requestCache,
BeanReference authenticationManager, BeanReference authenticationFilterSecurityContextRepositoryRef,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategy) {
BeanReference authenticationManager, BeanReference authenticationFilterSecurityContextRepositoryRef) {
createOAuth2LoginFilter(sessionStrategy, authenticationManager,
authenticationFilterSecurityContextRepositoryRef, authenticationFilterSecurityContextHolderStrategy);
createOAuth2ClientFilter(requestCache, authenticationManager, authenticationFilterSecurityContextRepositoryRef,
authenticationFilterSecurityContextHolderStrategy);
authenticationFilterSecurityContextRepositoryRef);
createOAuth2ClientFilter(requestCache, authenticationManager, authenticationFilterSecurityContextRepositoryRef);
registerOAuth2ClientPostProcessors();
}
void createOAuth2LoginFilter(BeanReference sessionStrategy, BeanReference authManager,
BeanReference authenticationFilterSecurityContextRepositoryRef,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategy) {
BeanReference authenticationFilterSecurityContextRepositoryRef) {
Element oauth2LoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OAUTH2_LOGIN);
if (oauth2LoginElt == null) {
return;
}
this.oauth2LoginEnabled = true;
OAuth2LoginBeanDefinitionParser parser = new OAuth2LoginBeanDefinitionParser(this.requestCache, this.portMapper,
this.portResolver, sessionStrategy, this.allowSessionCreation,
authenticationFilterSecurityContextHolderStrategy);
this.portResolver, sessionStrategy, this.allowSessionCreation);
BeanDefinition oauth2LoginFilterBean = parser.parse(oauth2LoginElt, this.pc);
BeanDefinition defaultAuthorizedClientRepository = parser.getDefaultAuthorizedClientRepository();
registerDefaultAuthorizedClientRepositoryIfNecessary(defaultAuthorizedClientRepository);
@@ -386,16 +375,14 @@ final class AuthenticationConfigBuilder {
}
void createOAuth2ClientFilter(BeanReference requestCache, BeanReference authenticationManager,
BeanReference authenticationFilterSecurityContextRepositoryRef,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategy) {
BeanReference authenticationFilterSecurityContextRepositoryRef) {
Element oauth2ClientElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OAUTH2_CLIENT);
if (oauth2ClientElt == null) {
return;
}
this.oauth2ClientEnabled = true;
OAuth2ClientBeanDefinitionParser parser = new OAuth2ClientBeanDefinitionParser(requestCache,
authenticationManager, authenticationFilterSecurityContextRepositoryRef,
authenticationFilterSecurityContextHolderStrategy);
authenticationManager, authenticationFilterSecurityContextRepositoryRef);
parser.parse(oauth2ClientElt, this.pc);
BeanDefinition defaultAuthorizedClientRepository = parser.getDefaultAuthorizedClientRepository();
registerDefaultAuthorizedClientRepositoryIfNecessary(defaultAuthorizedClientRepository);
@@ -577,8 +564,7 @@ final class AuthenticationConfigBuilder {
}
}
void createBasicFilter(BeanReference authManager,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
void createBasicFilter(BeanReference authManager) {
Element basicAuthElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.BASIC_AUTH);
if (basicAuthElt == null && !this.autoConfig) {
// No basic auth, do nothing
@@ -606,13 +592,10 @@ final class AuthenticationConfigBuilder {
}
filterBuilder.addConstructorArgValue(authManager);
filterBuilder.addConstructorArgValue(this.basicEntryPoint);
filterBuilder.addPropertyValue("securityContextHolderStrategy",
authenticationFilterSecurityContextHolderStrategyRef);
this.basicFilter = filterBuilder.getBeanDefinition();
}
void createBearerTokenAuthenticationFilter(BeanReference authManager,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
void createBearerTokenAuthenticationFilter(BeanReference authManager) {
Element resourceServerElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OAUTH2_RESOURCE_SERVER);
if (resourceServerElt == null) {
// No resource server, do nothing
@@ -620,13 +603,11 @@ final class AuthenticationConfigBuilder {
}
OAuth2ResourceServerBeanDefinitionParser resourceServerBuilder = new OAuth2ResourceServerBeanDefinitionParser(
authManager, this.authenticationProviders, this.defaultEntryPointMappings,
this.defaultDeniedHandlerMappings, this.csrfIgnoreRequestMatchers,
authenticationFilterSecurityContextHolderStrategyRef);
this.defaultDeniedHandlerMappings, this.csrfIgnoreRequestMatchers);
this.bearerTokenAuthenticationFilter = resourceServerBuilder.parse(resourceServerElt, this.pc);
}
void createX509Filter(BeanReference authManager,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
void createX509Filter(BeanReference authManager) {
Element x509Elt = DomUtils.getChildElementByTagName(this.httpElt, Elements.X509);
RootBeanDefinition filter = null;
if (x509Elt != null) {
@@ -634,8 +615,6 @@ final class AuthenticationConfigBuilder {
.rootBeanDefinition(X509AuthenticationFilter.class);
filterBuilder.getRawBeanDefinition().setSource(this.pc.extractSource(x509Elt));
filterBuilder.addPropertyValue("authenticationManager", authManager);
filterBuilder.addPropertyValue("securityContextHolderStrategy",
authenticationFilterSecurityContextHolderStrategyRef);
String regex = x509Elt.getAttribute("subject-principal-regex");
if (StringUtils.hasText(regex)) {
BeanDefinitionBuilder extractor = BeanDefinitionBuilder
@@ -676,8 +655,7 @@ final class AuthenticationConfigBuilder {
}
}
void createJeeFilter(BeanReference authManager,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
void createJeeFilter(BeanReference authManager) {
Element jeeElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.JEE);
RootBeanDefinition filter = null;
if (jeeElt != null) {
@@ -685,8 +663,6 @@ final class AuthenticationConfigBuilder {
.rootBeanDefinition(J2eePreAuthenticatedProcessingFilter.class);
filterBuilder.getRawBeanDefinition().setSource(this.pc.extractSource(jeeElt));
filterBuilder.addPropertyValue("authenticationManager", authManager);
filterBuilder.addPropertyValue("securityContextHolderStrategy",
authenticationFilterSecurityContextHolderStrategyRef);
BeanDefinitionBuilder adsBldr = BeanDefinitionBuilder
.rootBeanDefinition(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class);
adsBldr.addPropertyValue("userRoles2GrantedAuthoritiesMapper",
@@ -763,7 +739,7 @@ final class AuthenticationConfigBuilder {
}
}
void createLogoutFilter(BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
void createLogoutFilter() {
Element logoutElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.LOGOUT);
if (logoutElt != null || this.autoConfig) {
String formLoginPage = this.formLoginPage;
@@ -771,21 +747,20 @@ final class AuthenticationConfigBuilder {
formLoginPage = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
}
LogoutBeanDefinitionParser logoutParser = new LogoutBeanDefinitionParser(formLoginPage,
this.rememberMeServicesId, this.csrfLogoutHandler,
authenticationFilterSecurityContextHolderStrategyRef);
this.rememberMeServicesId, this.csrfLogoutHandler);
this.logoutFilter = logoutParser.parse(logoutElt, this.pc);
this.logoutHandlers = logoutParser.getLogoutHandlers();
this.logoutSuccessHandler = logoutParser.getLogoutSuccessHandler();
}
}
private void createSaml2LogoutFilter(BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
private void createSaml2LogoutFilter() {
Element saml2LogoutElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.SAML2_LOGOUT);
if (saml2LogoutElt == null) {
return;
}
Saml2LogoutBeanDefinitionParser parser = new Saml2LogoutBeanDefinitionParser(this.logoutHandlers,
this.logoutSuccessHandler, authenticationFilterSecurityContextHolderStrategyRef);
this.logoutSuccessHandler);
parser.parse(saml2LogoutElt, this.pc);
BeanDefinition saml2LogoutFilter = parser.getLogoutFilter();
BeanDefinition saml2LogoutRequestFilter = parser.getLogoutRequestFilter();
@@ -828,7 +803,7 @@ final class AuthenticationConfigBuilder {
return this.csrfIgnoreRequestMatchers;
}
void createAnonymousFilter(BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
void createAnonymousFilter() {
Element anonymousElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.ANONYMOUS);
if (anonymousElt != null && "false".equals(anonymousElt.getAttribute("enabled"))) {
return;
@@ -858,8 +833,6 @@ final class AuthenticationConfigBuilder {
this.anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(1, username);
this.anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(2,
AuthorityUtils.commaSeparatedStringToAuthorityList(grantedAuthority));
this.anonymousFilter.getPropertyValues().addPropertyValue("securityContextHolderStrategy",
authenticationFilterSecurityContextHolderStrategyRef);
this.anonymousFilter.setSource(source);
RootBeanDefinition anonymousProviderBean = new RootBeanDefinition(AnonymousAuthenticationProvider.class);
anonymousProviderBean.getConstructorArgumentValues().addIndexedArgumentValue(0, key);
@@ -874,7 +847,7 @@ final class AuthenticationConfigBuilder {
return Long.toString(random.nextLong());
}
void createExceptionTranslationFilter(BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
void createExceptionTranslationFilter() {
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
this.accessDeniedHandler = createAccessDeniedHandler(this.httpElt, this.pc);
etfBuilder.addPropertyValue("accessDeniedHandler", this.accessDeniedHandler);
@@ -882,8 +855,6 @@ final class AuthenticationConfigBuilder {
this.mainEntryPoint = selectEntryPoint();
etfBuilder.addConstructorArgValue(this.mainEntryPoint);
etfBuilder.addConstructorArgValue(this.requestCache);
etfBuilder.addPropertyValue("securityContextHolderStrategy",
authenticationFilterSecurityContextHolderStrategyRef);
this.etf = etfBuilder.getBeanDefinition();
}
@@ -1,203 +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.http;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.config.Elements;
import org.springframework.security.web.access.expression.DefaultHttpSecurityExpressionHandler;
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
class AuthorizationFilterParser implements BeanDefinitionParser {
private static final String ATT_USE_EXPRESSIONS = "use-expressions";
private static final String ATT_ACCESS_DECISION_MANAGER_REF = "access-decision-manager-ref";
private static final String ATT_HTTP_METHOD = "method";
private static final String ATT_PATTERN = "pattern";
private static final String ATT_ACCESS = "access";
private static final String ATT_SERVLET_PATH = "servlet-path";
private static final String ATT_FILTER_ALL_DISPATCHER_TYPES = "filter-all-dispatcher-types";
private String authorizationManagerRef;
private final BeanMetadataElement securityContextHolderStrategy;
AuthorizationFilterParser(BeanMetadataElement securityContextHolderStrategy) {
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
if (!isUseExpressions(element)) {
parserContext.getReaderContext().error("AuthorizationManager must be used with `use-expressions=\"true\"",
element);
return null;
}
if (StringUtils.hasText(element.getAttribute(ATT_ACCESS_DECISION_MANAGER_REF))) {
parserContext.getReaderContext().error(
"AuthorizationManager cannot be used in conjunction with `access-decision-manager-ref`", element);
return null;
}
this.authorizationManagerRef = createAuthorizationManager(element, parserContext);
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(AuthorizationFilter.class);
filterBuilder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
filterBuilder.addConstructorArgReference(this.authorizationManagerRef);
if ("true".equals(element.getAttribute(ATT_FILTER_ALL_DISPATCHER_TYPES))) {
filterBuilder.addPropertyValue("shouldFilterAllDispatcherTypes", Boolean.TRUE);
}
BeanDefinition filter = filterBuilder
.addPropertyValue("securityContextHolderStrategy", this.securityContextHolderStrategy)
.getBeanDefinition();
String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
if (StringUtils.hasText(id)) {
parserContext.registerComponent(new BeanComponentDefinition(filter, id));
parserContext.getRegistry().registerBeanDefinition(id, filter);
}
return filter;
}
String getAuthorizationManagerRef() {
return this.authorizationManagerRef;
}
private String createAuthorizationManager(Element element, ParserContext parserContext) {
XmlReaderContext context = parserContext.getReaderContext();
String authorizationManagerRef = element.getAttribute("authorization-manager-ref");
if (StringUtils.hasText(authorizationManagerRef)) {
return authorizationManagerRef;
}
Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER);
String expressionHandlerRef = (expressionHandlerElt != null) ? expressionHandlerElt.getAttribute("ref") : null;
if (expressionHandlerRef == null) {
expressionHandlerRef = registerDefaultExpressionHandler(parserContext);
}
MatcherType matcherType = MatcherType.fromElement(element);
ManagedMap<BeanMetadataElement, BeanDefinition> matcherToExpression = new ManagedMap<>();
List<Element> interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
for (Element interceptMessage : interceptMessages) {
String accessExpression = interceptMessage.getAttribute(ATT_ACCESS);
BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder
.rootBeanDefinition(WebExpressionAuthorizationManager.class);
authorizationManager.addPropertyReference("expressionHandler", expressionHandlerRef);
authorizationManager.addConstructorArgValue(accessExpression);
BeanMetadataElement matcher = createMatcher(matcherType, interceptMessage, parserContext);
matcherToExpression.put(matcher, authorizationManager.getBeanDefinition());
}
BeanDefinitionBuilder mds = BeanDefinitionBuilder
.rootBeanDefinition(RequestMatcherDelegatingAuthorizationManagerFactory.class);
mds.setFactoryMethod("createRequestMatcherDelegatingAuthorizationManager");
mds.addConstructorArgValue(matcherToExpression);
return context.registerWithGeneratedName(mds.getBeanDefinition());
}
private BeanMetadataElement createMatcher(MatcherType matcherType, Element urlElt, ParserContext parserContext) {
String path = urlElt.getAttribute(ATT_PATTERN);
String matcherRef = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF);
boolean hasMatcherRef = StringUtils.hasText(matcherRef);
if (!hasMatcherRef && !StringUtils.hasText(path)) {
parserContext.getReaderContext().error("path attribute cannot be empty or null", urlElt);
}
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
if (!StringUtils.hasText(method)) {
method = null;
}
String servletPath = urlElt.getAttribute(ATT_SERVLET_PATH);
if (!StringUtils.hasText(servletPath)) {
servletPath = null;
}
else if (!MatcherType.mvc.equals(matcherType)) {
parserContext.getReaderContext().error(
ATT_SERVLET_PATH + " is not applicable for request-matcher: '" + matcherType.name() + "'", urlElt);
}
return hasMatcherRef ? new RuntimeBeanReference(matcherRef)
: matcherType.createMatcher(parserContext, path, method, servletPath);
}
String registerDefaultExpressionHandler(ParserContext pc) {
BeanDefinition expressionHandler = GrantedAuthorityDefaultsParserUtils.registerWithDefaultRolePrefix(pc,
DefaultWebSecurityExpressionHandlerBeanFactory.class);
String expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandler);
pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef));
return expressionHandlerRef;
}
boolean isUseExpressions(Element elt) {
String useExpressions = elt.getAttribute(ATT_USE_EXPRESSIONS);
return !StringUtils.hasText(useExpressions) || "true".equals(useExpressions);
}
private static class RequestMatcherDelegatingAuthorizationManagerFactory {
private static AuthorizationManager<HttpServletRequest> createRequestMatcherDelegatingAuthorizationManager(
Map<RequestMatcher, AuthorizationManager<RequestAuthorizationContext>> beans) {
RequestMatcherDelegatingAuthorizationManager.Builder builder = RequestMatcherDelegatingAuthorizationManager
.builder();
for (Map.Entry<RequestMatcher, AuthorizationManager<RequestAuthorizationContext>> entry : beans
.entrySet()) {
builder.add(entry.getKey(), entry.getValue());
}
return builder.add(AnyRequestMatcher.INSTANCE, AuthenticatedAuthorizationManager.authenticated()).build();
}
}
static class DefaultWebSecurityExpressionHandlerBeanFactory
extends GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory {
private DefaultHttpSecurityExpressionHandler handler = new DefaultHttpSecurityExpressionHandler();
@Override
public DefaultHttpSecurityExpressionHandler getBean() {
if (this.rolePrefix != null) {
this.handler.setDefaultRolePrefix(this.rolePrefix);
}
return this.handler;
}
}
}
@@ -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.
@@ -71,16 +71,12 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_REPOSITORY = "token-repository-ref";
private static final String ATT_REQUEST_HANDLER = "request-handler-ref";
private String csrfRepositoryRef;
private BeanDefinition csrfFilter;
private String requestMatcherRef;
private String requestHandlerRef;
@Override
public BeanDefinition parse(Element element, ParserContext pc) {
boolean disabled = element != null && "true".equals(element.getAttribute("disabled"));
@@ -99,7 +95,6 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
if (element != null) {
this.csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
this.requestMatcherRef = element.getAttribute(ATT_MATCHER);
this.requestHandlerRef = element.getAttribute(ATT_REQUEST_HANDLER);
}
if (!StringUtils.hasText(this.csrfRepositoryRef)) {
RootBeanDefinition csrfTokenRepository = new RootBeanDefinition(HttpSessionCsrfTokenRepository.class);
@@ -115,9 +110,6 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
if (StringUtils.hasText(this.requestMatcherRef)) {
builder.addPropertyReference("requireCsrfProtectionMatcher", this.requestMatcherRef);
}
if (StringUtils.hasText(this.requestHandlerRef)) {
builder.addPropertyReference("requestHandler", this.requestHandlerRef);
}
this.csrfFilter = builder.getBeanDefinition();
return this.csrfFilter;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,13 +18,10 @@ package org.springframework.security.config.http;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Supplier;
import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -32,16 +29,11 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
@@ -58,8 +50,6 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
public class DefaultFilterChainValidator implements FilterChainProxy.FilterChainValidator {
private static final Authentication TEST = new TestingAuthenticationToken("", "", Collections.emptyList());
private final Log logger = LogFactory.getLog(getClass());
@Override
@@ -120,7 +110,6 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
checkForDuplicates(JaasApiIntegrationFilter.class, filters);
checkForDuplicates(ExceptionTranslationFilter.class, filters);
checkForDuplicates(FilterSecurityInterceptor.class, filters);
checkForDuplicates(AuthorizationFilter.class, filters);
}
private void checkForDuplicates(Class<? extends Filter> clazz, List<Filter> filters) {
@@ -145,13 +134,11 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
* interceptor
*/
private void checkLoginPageIsntProtected(FilterChainProxy fcp, List<Filter> filterStack) {
ExceptionTranslationFilter exceptions = getFilter(ExceptionTranslationFilter.class, filterStack);
if (exceptions == null
|| !(exceptions.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint)) {
ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class, filterStack);
if (etf == null || !(etf.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint)) {
return;
}
String loginPage = ((LoginUrlAuthenticationEntryPoint) exceptions.getAuthenticationEntryPoint())
.getLoginFormUrl();
String loginPage = ((LoginUrlAuthenticationEntryPoint) etf.getAuthenticationEntryPoint()).getLoginFormUrl();
this.logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration");
FilterInvocation loginRequest = new FilterInvocation(loginPage, "POST");
List<Filter> filters = null;
@@ -172,26 +159,33 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
this.logger.debug("Default generated login page is in use");
return;
}
if (checkLoginPageIsPublic(filters, loginRequest)) {
FilterSecurityInterceptor fsi = getFilter(FilterSecurityInterceptor.class, filters);
FilterInvocationSecurityMetadataSource fids = fsi.getSecurityMetadataSource();
Collection<ConfigAttribute> attributes = fids.getAttributes(loginRequest);
if (attributes == null) {
this.logger.debug("No access attributes defined for login page URL");
if (fsi.isRejectPublicInvocations()) {
this.logger.warn("FilterSecurityInterceptor is configured to reject public invocations."
+ " Your login page may not be accessible.");
}
return;
}
AnonymousAuthenticationFilter anonymous = getFilter(AnonymousAuthenticationFilter.class, filters);
if (anonymous == null) {
AnonymousAuthenticationFilter anonPF = getFilter(AnonymousAuthenticationFilter.class, filters);
if (anonPF == null) {
this.logger.warn("The login page is being protected by the filter chain, but you don't appear to have"
+ " anonymous authentication enabled. This is almost certainly an error.");
return;
}
// Simulate an anonymous access with the supplied attributes.
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("key", anonymous.getPrincipal(),
anonymous.getAuthorities());
Supplier<Boolean> check = deriveAnonymousCheck(filters, loginRequest, token);
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("key", anonPF.getPrincipal(),
anonPF.getAuthorities());
try {
boolean allowed = check.get();
if (!allowed) {
this.logger.warn("Anonymous access to the login page doesn't appear to be enabled. "
+ "This is almost certainly an error. Please check your configuration allows unauthenticated "
+ "access to the configured login page. (Simulated access was rejected)");
}
fsi.getAccessDecisionManager().decide(token, loginRequest, attributes);
}
catch (AccessDeniedException ex) {
this.logger.warn("Anonymous access to the login page doesn't appear to be enabled. "
+ "This is almost certainly an error. Please check your configuration allows unauthenticated "
+ "access to the configured login page. (Simulated access was rejected: " + ex + ")");
}
catch (Exception ex) {
// May happen legitimately if a filter-chain request matcher requires more
@@ -202,62 +196,4 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
}
}
private boolean checkLoginPageIsPublic(List<Filter> filters, FilterInvocation loginRequest) {
FilterSecurityInterceptor authorizationInterceptor = getFilter(FilterSecurityInterceptor.class, filters);
if (authorizationInterceptor != null) {
FilterInvocationSecurityMetadataSource fids = authorizationInterceptor.getSecurityMetadataSource();
Collection<ConfigAttribute> attributes = fids.getAttributes(loginRequest);
if (attributes == null) {
this.logger.debug("No access attributes defined for login page URL");
if (authorizationInterceptor.isRejectPublicInvocations()) {
this.logger.warn("FilterSecurityInterceptor is configured to reject public invocations."
+ " Your login page may not be accessible.");
}
return true;
}
return false;
}
AuthorizationFilter authorizationFilter = getFilter(AuthorizationFilter.class, filters);
if (authorizationFilter != null) {
AuthorizationManager<HttpServletRequest> authorizationManager = authorizationFilter
.getAuthorizationManager();
try {
AuthorizationDecision decision = authorizationManager.check(() -> TEST, loginRequest.getHttpRequest());
return decision != null && decision.isGranted();
}
catch (Exception ex) {
return false;
}
}
return false;
}
private Supplier<Boolean> deriveAnonymousCheck(List<Filter> filters, FilterInvocation loginRequest,
AnonymousAuthenticationToken token) {
FilterSecurityInterceptor authorizationInterceptor = getFilter(FilterSecurityInterceptor.class, filters);
if (authorizationInterceptor != null) {
return () -> {
FilterInvocationSecurityMetadataSource source = authorizationInterceptor.getSecurityMetadataSource();
Collection<ConfigAttribute> attributes = source.getAttributes(loginRequest);
try {
authorizationInterceptor.getAccessDecisionManager().decide(token, loginRequest, attributes);
return true;
}
catch (AccessDeniedException ex) {
return false;
}
};
}
AuthorizationFilter authorizationFilter = getFilter(AuthorizationFilter.class, filters);
if (authorizationFilter != null) {
return () -> {
AuthorizationManager<HttpServletRequest> authorizationManager = authorizationFilter
.getAuthorizationManager();
AuthorizationDecision decision = authorizationManager.check(() -> token, loginRequest.getHttpRequest());
return decision != null && decision.isGranted();
};
}
return () -> true;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,9 +46,7 @@ import org.springframework.util.xml.DomUtils;
* for use with a FilterSecurityInterceptor.
*
* @author Luke Taylor
* @deprecated Use `use-authorization-manager` property instead
*/
@Deprecated
public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinitionParser {
private static final String ATT_USE_EXPRESSIONS = "use-expressions";
@@ -101,8 +101,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_POLICY_DIRECTIVES = "policy-directives";
private static final String ATT_HEADER_VALUE = "header-value";
private static final String CACHE_CONTROL_ELEMENT = "cache-control";
private static final String HPKP_ELEMENT = "hpkp";
@@ -597,14 +595,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
}
builder.addPropertyValue("block", block);
}
XXssProtectionHeaderWriter.HeaderValue headerValue = XXssProtectionHeaderWriter.HeaderValue
.from(xssElt.getAttribute(ATT_HEADER_VALUE));
if (headerValue != null) {
if (disabled) {
attrNotAllowed(parserContext, ATT_HEADER_VALUE, ATT_DISABLED, xssElt);
}
builder.addPropertyValue("headerValue", headerValue);
}
if (disabled) {
return;
}
@@ -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.
@@ -24,7 +24,6 @@ import javax.servlet.ServletRequest;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
@@ -41,10 +40,7 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.config.Elements;
import org.springframework.security.config.http.GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
@@ -103,16 +99,12 @@ class HttpConfigurationBuilder {
private static final String OPT_CHANGE_SESSION_ID = "changeSessionId";
private static final String ATT_AUTHENTICATION_STRATEGY_EXPLICIT_INVOCATION = "authentication-strategy-explicit-invocation";
private static final String ATT_INVALID_SESSION_URL = "invalid-session-url";
private static final String ATT_SESSION_AUTH_STRATEGY_REF = "session-authentication-strategy-ref";
private static final String ATT_SESSION_AUTH_ERROR_URL = "session-authentication-error-url";
private static final String ATT_SECURITY_CONTEXT_HOLDER_STRATEGY = "security-context-holder-strategy-ref";
private static final String ATT_SECURITY_CONTEXT_REPOSITORY = "security-context-repository-ref";
private static final String ATT_SECURITY_CONTEXT_EXPLICIT_SAVE = "security-context-explicit-save";
@@ -121,10 +113,6 @@ class HttpConfigurationBuilder {
private static final String ATT_DISABLE_URL_REWRITING = "disable-url-rewriting";
private static final String ATT_USE_AUTHORIZATION_MGR = "use-authorization-manager";
private static final String ATT_AUTHORIZATION_MGR = "authorization-manager-ref";
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
private static final String ATT_ONCE_PER_REQUEST = "once-per-request";
@@ -163,8 +151,6 @@ class HttpConfigurationBuilder {
private BeanDefinition forceEagerSessionCreationFilter;
private BeanMetadataElement holderStrategyRef;
private BeanReference contextRepoRef;
private BeanReference sessionRegistryRef;
@@ -224,7 +210,6 @@ class HttpConfigurationBuilder {
String createSession = element.getAttribute(ATT_CREATE_SESSION);
this.sessionPolicy = !StringUtils.hasText(createSession) ? SessionCreationPolicy.IF_REQUIRED
: createPolicy(createSession);
createSecurityContextHolderStrategy();
createForceEagerSessionCreationFilter();
createDisableEncodeUrlFilter();
createCsrfFilter();
@@ -235,7 +220,7 @@ class HttpConfigurationBuilder {
createServletApiFilter(authenticationManager);
createJaasApiFilter();
createChannelProcessingFilter();
createFilterSecurity(authenticationManager);
createFilterSecurityInterceptor(authenticationManager);
createAddHeadersFilter();
createCorsFilter();
createWellKnownChangePasswordRedirectFilter();
@@ -304,10 +289,6 @@ class HttpConfigurationBuilder {
return lowerCase ? path.toLowerCase() : path;
}
BeanMetadataElement getSecurityContextHolderStrategyForAuthenticationFilters() {
return this.holderStrategyRef;
}
BeanReference getSecurityContextRepositoryForAuthenticationFilters() {
return (isExplicitSave()) ? this.contextRepoRef : null;
}
@@ -345,22 +326,11 @@ class HttpConfigurationBuilder {
default:
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
}
scpf.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
scpf.addConstructorArgValue(this.contextRepoRef);
this.securityContextPersistenceFilter = scpf.getBeanDefinition();
}
private void createSecurityContextHolderStrategy() {
String holderStrategyRef = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_HOLDER_STRATEGY);
if (StringUtils.hasText(holderStrategyRef)) {
this.holderStrategyRef = new RuntimeBeanReference(holderStrategyRef);
return;
}
this.holderStrategyRef = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextHolderStrategyFactory.class)
.getBeanDefinition();
}
private void createSecurityContextRepository() {
String repoRef = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_REPOSITORY);
if (!StringUtils.hasText(repoRef)) {
@@ -384,7 +354,6 @@ class HttpConfigurationBuilder {
contextRepo.addPropertyValue("disableUrlRewriting", Boolean.TRUE);
}
}
contextRepo.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
BeanDefinition repoBean = contextRepo.getBeanDefinition();
repoRef = this.pc.getReaderContext().generateBeanName(repoBean);
this.pc.registerBeanComponent(new BeanComponentDefinition(repoBean, repoRef));
@@ -400,7 +369,6 @@ class HttpConfigurationBuilder {
private void createSecurityContextHolderFilter() {
BeanDefinitionBuilder filter = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextHolderFilter.class);
filter.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
filter.addConstructorArgValue(this.contextRepoRef);
this.securityContextPersistenceFilter = filter.getBeanDefinition();
}
@@ -512,7 +480,6 @@ class HttpConfigurationBuilder {
if (StringUtils.hasText(errorUrl)) {
failureHandler.getPropertyValues().addPropertyValue("defaultFailureUrl", errorUrl);
}
sessionMgmtFilter.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
sessionMgmtFilter.addPropertyValue("authenticationFailureHandler", failureHandler);
sessionMgmtFilter.addConstructorArgValue(this.contextRepoRef);
if (!StringUtils.hasText(sessionAuthStratRef) && sessionFixationStrategy != null && !useChangeSessionId) {
@@ -540,11 +507,7 @@ class HttpConfigurationBuilder {
sessionMgmtFilter.addPropertyReference("invalidSessionStrategy", invalidSessionStrategyRef);
}
sessionMgmtFilter.addConstructorArgReference(sessionAuthStratRef);
boolean registerSessionMgmtFilter = (sessionMgmtElt == null
|| !"true".equals(sessionMgmtElt.getAttribute(ATT_AUTHENTICATION_STRATEGY_EXPLICIT_INVOCATION)));
if (registerSessionMgmtFilter) {
this.sfpf = (RootBeanDefinition) sessionMgmtFilter.getBeanDefinition();
}
this.sfpf = (RootBeanDefinition) sessionMgmtFilter.getBeanDefinition();
this.sessionStrategyRef = new RuntimeBeanReference(sessionAuthStratRef);
}
@@ -594,7 +557,6 @@ class HttpConfigurationBuilder {
boolean asyncSupported = ClassUtils.hasMethod(ServletRequest.class, "startAsync");
if (asyncSupported) {
this.webAsyncManagerFilter = new RootBeanDefinition(WebAsyncManagerIntegrationFilter.class);
this.webAsyncManagerFilter.getPropertyValues().add("securityContextHolderStrategy", this.holderStrategyRef);
}
}
@@ -608,7 +570,6 @@ class HttpConfigurationBuilder {
this.servApiFilter = GrantedAuthorityDefaultsParserUtils.registerWithDefaultRolePrefix(this.pc,
SecurityContextHolderAwareRequestFilterBeanFactory.class);
this.servApiFilter.getPropertyValues().add("authenticationManager", authenticationManager);
this.servApiFilter.getPropertyValues().add("securityContextHolderStrategy", this.holderStrategyRef);
}
}
@@ -619,8 +580,7 @@ class HttpConfigurationBuilder {
provideJaasApi = DEF_JAAS_API_PROVISION;
}
if ("true".equals(provideJaasApi)) {
this.jaasApiFilter = BeanDefinitionBuilder.rootBeanDefinition(JaasApiIntegrationFilter.class)
.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef).getBeanDefinition();
this.jaasApiFilter = new RootBeanDefinition(JaasApiIntegrationFilter.class);
}
}
@@ -715,35 +675,6 @@ class HttpConfigurationBuilder {
this.requestCacheAwareFilter.getConstructorArgumentValues().addGenericArgumentValue(this.requestCache);
}
private void createFilterSecurity(BeanReference authManager) {
boolean useAuthorizationManager = Boolean.parseBoolean(this.httpElt.getAttribute(ATT_USE_AUTHORIZATION_MGR));
if (useAuthorizationManager) {
createAuthorizationFilter();
return;
}
if (StringUtils.hasText(this.httpElt.getAttribute(ATT_AUTHORIZATION_MGR))) {
createAuthorizationFilter();
return;
}
createFilterSecurityInterceptor(authManager);
}
private void createAuthorizationFilter() {
AuthorizationFilterParser authorizationFilterParser = new AuthorizationFilterParser(this.holderStrategyRef);
BeanDefinition fsiBean = authorizationFilterParser.parse(this.httpElt, this.pc);
String fsiId = this.pc.getReaderContext().generateBeanName(fsiBean);
this.pc.registerBeanComponent(new BeanComponentDefinition(fsiBean, fsiId));
// Create and register a AuthorizationManagerWebInvocationPrivilegeEvaluator for
// use with
// taglibs etc.
BeanDefinition wipe = BeanDefinitionBuilder
.rootBeanDefinition(AuthorizationManagerWebInvocationPrivilegeEvaluator.class)
.addConstructorArgReference(authorizationFilterParser.getAuthorizationManagerRef()).getBeanDefinition();
this.pc.registerBeanComponent(
new BeanComponentDefinition(wipe, this.pc.getReaderContext().generateBeanName(wipe)));
this.fsi = new RuntimeBeanReference(fsiId);
}
private void createFilterSecurityInterceptor(BeanReference authManager) {
boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(this.httpElt);
RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser
@@ -779,7 +710,6 @@ class HttpConfigurationBuilder {
builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
}
builder.addPropertyValue("securityMetadataSource", securityMds);
builder.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
BeanDefinition fsiBean = builder.getBeanDefinition();
String fsiId = this.pc.getReaderContext().generateBeanName(fsiBean);
this.pc.registerBeanComponent(new BeanComponentDefinition(fsiBean, fsiId));
@@ -911,34 +841,12 @@ class HttpConfigurationBuilder {
private SecurityContextHolderAwareRequestFilter filter = new SecurityContextHolderAwareRequestFilter();
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
@Override
public SecurityContextHolderAwareRequestFilter getBean() {
this.filter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
this.filter.setRolePrefix(this.rolePrefix);
return this.filter;
}
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
}
static class SecurityContextHolderStrategyFactory implements FactoryBean<SecurityContextHolderStrategy> {
@Override
public SecurityContextHolderStrategy getObject() throws Exception {
return SecurityContextHolder.getContextHolderStrategy();
}
@Override
public Class<?> getObjectType() {
return SecurityContextHolderStrategy.class;
}
}
}
@@ -147,7 +147,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
httpBldr.getSecurityContextRepositoryForAuthenticationFilters();
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, forceAutoConfig, pc,
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
httpBldr.getSecurityContextHolderStrategyForAuthenticationFilters(),
httpBldr.getSecurityContextRepositoryForAuthenticationFilters(), httpBldr.getSessionStrategy(),
portMapper, portResolver, httpBldr.getCsrfLogoutHandler());
httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,17 +61,13 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
private BeanMetadataElement logoutSuccessHandler;
private BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef;
LogoutBeanDefinitionParser(String loginPageUrl, String rememberMeServices, BeanMetadataElement csrfLogoutHandler,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategyRef) {
LogoutBeanDefinitionParser(String loginPageUrl, String rememberMeServices, BeanMetadataElement csrfLogoutHandler) {
this.defaultLogoutUrl = loginPageUrl + "?logout";
this.rememberMeServices = rememberMeServices;
this.csrfEnabled = csrfLogoutHandler != null;
if (this.csrfEnabled) {
this.logoutHandlers.add(csrfLogoutHandler);
}
this.authenticationFilterSecurityContextHolderStrategyRef = authenticationFilterSecurityContextHolderStrategyRef;
}
@Override
@@ -127,8 +123,6 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
}
this.logoutHandlers.add(new RootBeanDefinition(LogoutSuccessEventPublishingLogoutHandler.class));
builder.addConstructorArgValue(this.logoutHandlers);
builder.addPropertyValue("securityContextHolderStrategy",
this.authenticationFilterSecurityContextHolderStrategyRef);
return builder.getBeanDefinition();
}
@@ -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.
@@ -44,8 +44,6 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_AUTHORIZATION_REQUEST_RESOLVER_REF = "authorization-request-resolver-ref";
private static final String ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF = "authorization-redirect-strategy-ref";
private static final String ATT_ACCESS_TOKEN_RESPONSE_CLIENT_REF = "access-token-response-client-ref";
private final BeanReference requestCache;
@@ -54,8 +52,6 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
private final BeanReference authenticationFilterSecurityContextRepositoryRef;
private final BeanMetadataElement authenticationFilterSecurityContextHolderStrategy;
private BeanDefinition defaultAuthorizedClientRepository;
private BeanDefinition authorizationRequestRedirectFilter;
@@ -65,12 +61,10 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
private BeanDefinition authorizationCodeAuthenticationProvider;
OAuth2ClientBeanDefinitionParser(BeanReference requestCache, BeanReference authenticationManager,
BeanReference authenticationFilterSecurityContextRepositoryRef,
BeanMetadataElement authenticationFilterSecurityContextHolderStrategy) {
BeanReference authenticationFilterSecurityContextRepositoryRef) {
this.requestCache = requestCache;
this.authenticationManager = authenticationManager;
this.authenticationFilterSecurityContextRepositoryRef = authenticationFilterSecurityContextRepositoryRef;
this.authenticationFilterSecurityContextHolderStrategy = authenticationFilterSecurityContextHolderStrategy;
}
@Override
@@ -89,7 +83,6 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
}
BeanMetadataElement authorizationRequestRepository = getAuthorizationRequestRepository(
authorizationCodeGrantElt);
BeanMetadataElement authorizationRedirectStrategy = getAuthorizationRedirectStrategy(authorizationCodeGrantElt);
BeanDefinitionBuilder authorizationRequestRedirectFilterBuilder = BeanDefinitionBuilder
.rootBeanDefinition(OAuth2AuthorizationRequestRedirectFilter.class);
String authorizationRequestResolverRef = (authorizationCodeGrantElt != null)
@@ -102,7 +95,6 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
}
this.authorizationRequestRedirectFilter = authorizationRequestRedirectFilterBuilder
.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository)
.addPropertyValue("authorizationRedirectStrategy", authorizationRedirectStrategy)
.addPropertyValue("requestCache", this.requestCache).getBeanDefinition();
BeanDefinitionBuilder authorizationCodeGrantFilterBldr = BeanDefinitionBuilder
.rootBeanDefinition(OAuth2AuthorizationCodeGrantFilter.class)
@@ -134,16 +126,6 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
.getBeanDefinition();
}
private BeanMetadataElement getAuthorizationRedirectStrategy(Element element) {
String authorizationRedirectStrategyRef = (element != null)
? element.getAttribute(ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF) : null;
if (StringUtils.hasText(authorizationRedirectStrategyRef)) {
return new RuntimeBeanReference(authorizationRedirectStrategyRef);
}
return BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.DefaultRedirectStrategy")
.getBeanDefinition();
}
private BeanMetadataElement getAccessTokenResponseClient(Element element) {
String accessTokenResponseClientRef = (element != null)
? element.getAttribute(ATT_ACCESS_TOKEN_RESPONSE_CLIENT_REF) : null;

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