diff --git a/.github/actions/algolia-config.json b/.github/actions/algolia-config.json
new file mode 100644
index 00000000000..09d30d486ea
--- /dev/null
+++ b/.github/actions/algolia-config.json
@@ -0,0 +1,20 @@
+{
+ "index_name": "security-docs",
+ "start_urls": [
+ "https://docs.spring.io/spring-security/reference/"
+ ],
+ "selectors": {
+ "lvl0": {
+ "selector": "//nav[@class='crumbs']//li[@class='crumb'][last()-1]",
+ "type": "xpath",
+ "global": true,
+ "default_value": "Home"
+ },
+ "lvl1": ".doc h1",
+ "lvl2": ".doc h2",
+ "lvl3": ".doc h3",
+ "lvl4": ".doc h4",
+ "text": ".doc p, .doc td.content, .doc th.tableblock"
+ }
+}
+
diff --git a/.github/actions/algolia-deploy.sh b/.github/actions/algolia-deploy.sh
new file mode 100755
index 00000000000..994dfee9ac9
--- /dev/null
+++ b/.github/actions/algolia-deploy.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+HOST="$1"
+HOST_PATH="$2"
+SSH_PRIVATE_KEY="$3"
+SSH_KNOWN_HOST="$4"
+
+
+if [ "$#" -ne 4 ]; then
+ echo -e "not enough arguments USAGE:\n\n$0 \$HOST \$HOST_PATH \$SSH_PRIVATE_KEY \$SSH_KNOWN_HOSTS \n\n" >&2
+ exit 1
+fi
+
+# Use a non-default path to avoid overriding when testing locally
+SSH_PRIVATE_KEY_PATH=~/.ssh/github-actions-docs
+install -m 600 -D /dev/null "$SSH_PRIVATE_KEY_PATH"
+echo "$SSH_PRIVATE_KEY" > "$SSH_PRIVATE_KEY_PATH"
+echo "$SSH_KNOWN_HOST" > ~/.ssh/known_hosts
+rsync --delete -avze "ssh -i $SSH_PRIVATE_KEY_PATH" docs/build/site/ "$HOST:$HOST_PATH"
+rm -f "$SSH_PRIVATE_KEY_PATH"
diff --git a/.github/actions/algolia-docsearch-scraper.sh b/.github/actions/algolia-docsearch-scraper.sh
new file mode 100755
index 00000000000..2bb9ce178ac
--- /dev/null
+++ b/.github/actions/algolia-docsearch-scraper.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+###
+# Docs
+# config.json https://docsearch.algolia.com/docs/config-file
+# Run the crawler https://docsearch.algolia.com/docs/run-your-own/#run-the-crawl-from-the-docker-image
+
+### USAGE
+if [ "$#" -ne 3 ]; then
+ echo -e "not enough arguments USAGE:\n\n$0 \$ALGOLIA_APPLICATION_ID \$ALGOLIA_API_KEY \$CONFIG_FILE\n\n" >&2
+ exit 1
+fi
+
+# Script Parameters
+APPLICATION_ID=$1
+API_KEY=$2
+CONFIG_FILE=$3
+
+#### Script
+script_dir=$(dirname $0)
+docker run -e "APPLICATION_ID=$APPLICATION_ID" -e "API_KEY=$API_KEY" -e "CONFIG=$(cat $CONFIG_FILE | jq -r tostring)" algolia/docsearch-scraper
diff --git a/.github/actions/dispatch.sh b/.github/actions/dispatch.sh
index d6c2a37794e..955e9cbbeef 100755
--- a/.github/actions/dispatch.sh
+++ b/.github/actions/dispatch.sh
@@ -1,5 +1,5 @@
REPOSITORY_REF="$1"
TOKEN="$2"
-curl -H "Accept: application/vnd.github.everest-preview+json" -H "Authorization: token ${TOKEN}" --request POST --data '{"event_type": "request-build"}' https://api.github.com/repos/${REPOSITORY_REF}/dispatches
-echo "Requested Build for $REPOSITORY_REF"
\ No newline at end of file
+curl -H "Accept: application/vnd.github.everest-preview+json" -H "Authorization: token ${TOKEN}" --request POST --data '{"event_type": "request-build-reference"}' https://api.github.com/repos/${REPOSITORY_REF}/dispatches
+echo "Requested Build for $REPOSITORY_REF"
diff --git a/.github/workflows/algolia-index.yml b/.github/workflows/algolia-index.yml
new file mode 100644
index 00000000000..dfc2295af33
--- /dev/null
+++ b/.github/workflows/algolia-index.yml
@@ -0,0 +1,16 @@
+name: Update Algolia Index
+
+on:
+ schedule:
+ - cron: '0 10 * * *' # Once per day at 10am UTC
+ workflow_dispatch: # Manual trigger
+
+jobs:
+ update:
+ name: Update Algolia Index
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Source
+ uses: actions/checkout@v2
+ - name: Update Index
+ run: ${GITHUB_WORKSPACE}/.github/actions/algolia-docsearch-scraper.sh "${{ secrets.ALGOLIA_APPLICATION_ID }}" "${{ secrets.ALGOLIA_WRITE_API_KEY }}" "${GITHUB_WORKSPACE}/.github/actions/algolia-config.json"
diff --git a/.github/workflows/build-reference.yml b/.github/workflows/antora-generate.yml
similarity index 91%
rename from .github/workflows/build-reference.yml
rename to .github/workflows/antora-generate.yml
index 7387f4a0407..f5cd25cfbf9 100644
--- a/.github/workflows/build-reference.yml
+++ b/.github/workflows/antora-generate.yml
@@ -1,4 +1,4 @@
-name: reference
+name: Generate Antora Files and Request Build
on:
push:
@@ -27,4 +27,4 @@ jobs:
repository-name: "spring-io/spring-generated-docs"
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Dispatch Build Request
- run: ${GITHUB_WORKSPACE}/.github/actions/dispatch.sh 'spring-io/spring-reference' "$GH_ACTIONS_REPO_TOKEN"
+ run: ${GITHUB_WORKSPACE}/.github/actions/dispatch.sh 'spring-projects/spring-security' "$GH_ACTIONS_REPO_TOKEN"
diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml
index d3679cc30fa..f9868aab190 100644
--- a/.github/workflows/continuous-integration-workflow.yml
+++ b/.github/workflows/continuous-integration-workflow.yml
@@ -29,8 +29,8 @@ jobs:
name: Determine if should continue
if: env.RUN_JOBS == 'true'
run: echo "::set-output name=runjobs::true"
- build_jdk_11:
- name: Build JDK 11
+ build_jdk_17:
+ name: Build JDK 17
needs: [prerequisites]
strategy:
matrix:
@@ -39,10 +39,10 @@ jobs:
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v2
- - name: Set up JDK 11
+ - name: Set up JDK 17
uses: actions/setup-java@v1
with:
- java-version: '11'
+ java-version: '17'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
@@ -68,7 +68,7 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v1
with:
- java-version: '11'
+ java-version: '17'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
@@ -89,7 +89,7 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v1
with:
- java-version: '11'
+ java-version: '17'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
@@ -110,7 +110,7 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v1
with:
- java-version: '11'
+ java-version: '17'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
@@ -123,14 +123,14 @@ jobs:
./gradlew check s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace
deploy_artifacts:
name: Deploy Artifacts
- needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
+ needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK
uses: actions/setup-java@v1
with:
- java-version: '11'
+ java-version: '17'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
@@ -150,14 +150,14 @@ jobs:
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
deploy_docs:
name: Deploy Docs
- needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
+ needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK
uses: actions/setup-java@v1
with:
- java-version: '11'
+ java-version: '17'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
@@ -174,14 +174,14 @@ jobs:
DOCS_HOST: ${{ secrets.DOCS_HOST }}
deploy_schema:
name: Deploy Schema
- needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
+ needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK
uses: actions/setup-java@v1
with:
- java-version: '11'
+ java-version: '17'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
@@ -198,7 +198,7 @@ jobs:
DOCS_HOST: ${{ secrets.DOCS_HOST }}
notify_result:
name: Check for failures
- needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles, deploy_artifacts, deploy_docs, deploy_schema]
+ needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles, deploy_artifacts, deploy_docs, deploy_schema]
if: failure()
runs-on: ubuntu-latest
steps:
diff --git a/.github/workflows/deploy-reference.yml b/.github/workflows/deploy-reference.yml
new file mode 100644
index 00000000000..a0033b926b0
--- /dev/null
+++ b/.github/workflows/deploy-reference.yml
@@ -0,0 +1,33 @@
+name: Build & Deploy Reference
+
+on:
+ repository_dispatch:
+ types: request-build-reference
+ schedule:
+ - cron: '0 10 * * *' # Once per day at 10am UTC
+ workflow_dispatch: # Manual trigger
+
+jobs:
+ deploy:
+ name: deploy
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 11
+ uses: actions/setup-java@v2
+ with:
+ java-version: '11'
+ distribution: 'adopt'
+ cache: gradle
+ - name: Validate Gradle wrapper
+ uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b
+ - name: Build with Gradle
+ run: ./gradlew :spring-security-docs:antora --stacktrace
+ - name: Cleanup Gradle Cache
+ # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
+ # Restoring these files from a GitHub Actions cache might cause problems for future builds.
+ run: |
+ rm -f ~/.gradle/caches/modules-2/modules-2.lock
+ rm -f ~/.gradle/caches/modules-2/gc.properties
+ - name: Deploy
+ run: ${GITHUB_WORKSPACE}/.github/actions/algolia-deploy.sh "${{ secrets.DOCS_USERNAME }}@${{ secrets.DOCS_HOST }}" "/opt/www/domains/spring.io/docs/htdocs/spring-security/reference/" "${{ secrets.DOCS_SSH_KEY }}" "${{ secrets.DOCS_SSH_HOST_KEY }}"
diff --git a/.github/workflows/pr-build-workflow.yml b/.github/workflows/pr-build-workflow.yml
index 0e7d5e7fdf0..d9a5c571343 100644
--- a/.github/workflows/pr-build-workflow.yml
+++ b/.github/workflows/pr-build-workflow.yml
@@ -16,7 +16,7 @@ jobs:
if: env.RUN_JOBS == 'true'
uses: actions/setup-java@v1
with:
- java-version: '11'
+ java-version: '17'
- name: Cache Gradle packages
if: env.RUN_JOBS == 'true'
uses: actions/cache@v2
diff --git a/README.adoc b/README.adoc
index 80d2f102e55..272b99ff6d0 100644
--- a/README.adoc
+++ b/README.adoc
@@ -6,8 +6,8 @@ image:https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?l
= Spring Security
-Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 5.0 requires Spring 5.0 as
-a minimum and also requires Java 8.
+Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 6.0 requires Spring 6.0 as
+a minimum and also requires Java 17.
For a detailed list of features and access to the latest release, please visit https://spring.io/projects[Spring projects].
@@ -30,9 +30,9 @@ In the instructions below, https://vimeo.com/34436402[`./gradlew`] is invoked fr
a cross-platform, self-contained bootstrap mechanism for the build.
=== Prerequisites
-https://help.github.com/set-up-git-redirect[Git] and the https://www.oracle.com/technetwork/java/javase/downloads[JDK11 build].
+https://help.github.com/set-up-git-redirect[Git] and the https://www.oracle.com/technetwork/java/javase/downloads[JDK17 build].
-Be sure that your `JAVA_HOME` environment variable points to the `jdk-11` folder extracted from the JDK download.
+Be sure that your `JAVA_HOME` environment variable points to the `jdk-17` folder extracted from the JDK download.
=== Check out sources
[indent=0]
diff --git a/acl/spring-security-acl.gradle b/acl/spring-security-acl.gradle
index 8de65558b88..976d8d42dbc 100644
--- a/acl/spring-security-acl.gradle
+++ b/acl/spring-security-acl.gradle
@@ -9,8 +9,6 @@ dependencies {
api 'org.springframework:spring-jdbc'
api 'org.springframework:spring-tx'
- optional 'net.sf.ehcache:ehcache'
-
testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
diff --git a/acl/src/main/java/org/springframework/security/acls/domain/EhCacheBasedAclCache.java b/acl/src/main/java/org/springframework/security/acls/domain/EhCacheBasedAclCache.java
deleted file mode 100644
index 9ad106d7afe..00000000000
--- a/acl/src/main/java/org/springframework/security/acls/domain/EhCacheBasedAclCache.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.acls.domain;
-
-import java.io.Serializable;
-
-import net.sf.ehcache.CacheException;
-import net.sf.ehcache.Ehcache;
-import net.sf.ehcache.Element;
-
-import org.springframework.security.acls.model.AclCache;
-import org.springframework.security.acls.model.MutableAcl;
-import org.springframework.security.acls.model.ObjectIdentity;
-import org.springframework.security.acls.model.PermissionGrantingStrategy;
-import org.springframework.security.util.FieldUtils;
-import org.springframework.util.Assert;
-
-/**
- * Simple implementation of {@link AclCache} that delegates to EH-CACHE.
- *
- * Designed to handle the transient fields in {@link AclImpl}. Note that this
- * implementation assumes all {@link AclImpl} instances share the same
- * {@link PermissionGrantingStrategy} and {@link AclAuthorizationStrategy} instances.
- *
- * @author Ben Alex
- * @deprecated since 5.6. In favor of JCache based implementations
- */
-@Deprecated
-public class EhCacheBasedAclCache implements AclCache {
-
- private final Ehcache cache;
-
- private PermissionGrantingStrategy permissionGrantingStrategy;
-
- private AclAuthorizationStrategy aclAuthorizationStrategy;
-
- public EhCacheBasedAclCache(Ehcache cache, PermissionGrantingStrategy permissionGrantingStrategy,
- AclAuthorizationStrategy aclAuthorizationStrategy) {
- Assert.notNull(cache, "Cache required");
- Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
- Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
- this.cache = cache;
- this.permissionGrantingStrategy = permissionGrantingStrategy;
- this.aclAuthorizationStrategy = aclAuthorizationStrategy;
- }
-
- @Override
- public void evictFromCache(Serializable pk) {
- Assert.notNull(pk, "Primary key (identifier) required");
- MutableAcl acl = getFromCache(pk);
- if (acl != null) {
- this.cache.remove(acl.getId());
- this.cache.remove(acl.getObjectIdentity());
- }
- }
-
- @Override
- public void evictFromCache(ObjectIdentity objectIdentity) {
- Assert.notNull(objectIdentity, "ObjectIdentity required");
- MutableAcl acl = getFromCache(objectIdentity);
- if (acl != null) {
- this.cache.remove(acl.getId());
- this.cache.remove(acl.getObjectIdentity());
- }
- }
-
- @Override
- public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
- Assert.notNull(objectIdentity, "ObjectIdentity required");
- try {
- Element element = this.cache.get(objectIdentity);
- return (element != null) ? initializeTransientFields((MutableAcl) element.getValue()) : null;
- }
- catch (CacheException ex) {
- return null;
- }
- }
-
- @Override
- public MutableAcl getFromCache(Serializable pk) {
- Assert.notNull(pk, "Primary key (identifier) required");
- try {
- Element element = this.cache.get(pk);
- return (element != null) ? initializeTransientFields((MutableAcl) element.getValue()) : null;
- }
- catch (CacheException ex) {
- return null;
- }
- }
-
- @Override
- public void putInCache(MutableAcl acl) {
- Assert.notNull(acl, "Acl required");
- Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
- Assert.notNull(acl.getId(), "ID required");
- if (this.aclAuthorizationStrategy == null) {
- if (acl instanceof AclImpl) {
- this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils
- .getProtectedFieldValue("aclAuthorizationStrategy", acl);
- this.permissionGrantingStrategy = (PermissionGrantingStrategy) FieldUtils
- .getProtectedFieldValue("permissionGrantingStrategy", acl);
- }
- }
- if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
- putInCache((MutableAcl) acl.getParentAcl());
- }
- this.cache.put(new Element(acl.getObjectIdentity(), acl));
- this.cache.put(new Element(acl.getId(), acl));
- }
-
- private MutableAcl initializeTransientFields(MutableAcl value) {
- if (value instanceof AclImpl) {
- FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
- FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
- }
- if (value.getParentAcl() != null) {
- initializeTransientFields((MutableAcl) value.getParentAcl());
- }
- return value;
- }
-
- @Override
- public void clearCache() {
- this.cache.removeAll();
- }
-
-}
diff --git a/acl/src/main/java/org/springframework/security/acls/jdbc/BasicLookupStrategy.java b/acl/src/main/java/org/springframework/security/acls/jdbc/BasicLookupStrategy.java
index 9d4d099b257..5f8db850e52 100644
--- a/acl/src/main/java/org/springframework/security/acls/jdbc/BasicLookupStrategy.java
+++ b/acl/src/main/java/org/springframework/security/acls/jdbc/BasicLookupStrategy.java
@@ -42,7 +42,7 @@
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
-import org.springframework.security.acls.domain.ObjectIdentityImpl;
+import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.PermissionFactory;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.AccessControlEntry;
@@ -51,6 +51,7 @@
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
+import org.springframework.security.acls.model.ObjectIdentityGenerator;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
@@ -109,6 +110,8 @@ public class BasicLookupStrategy implements LookupStrategy {
private final AclAuthorizationStrategy aclAuthorizationStrategy;
+ private ObjectIdentityGenerator objectIdentityGenerator;
+
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
private final AclCache aclCache;
@@ -162,6 +165,7 @@ public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
this.aclCache = aclCache;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.grantingStrategy = grantingStrategy;
+ this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
this.aclClassIdUtils = new AclClassIdUtils();
this.fieldAces.setAccessible(true);
this.fieldAcl.setAccessible(true);
@@ -488,6 +492,11 @@ public final void setAclClassIdSupported(boolean aclClassIdSupported) {
}
}
+ public final void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
+ Assert.notNull(objectIdentityGenerator, "objectIdentityGenerator cannot be null");
+ this.objectIdentityGenerator = objectIdentityGenerator;
+ }
+
public final void setConversionService(ConversionService conversionService) {
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
}
@@ -569,7 +578,8 @@ private void convertCurrentResultIntoObject(Map acls, ResultS
// target id type, e.g. UUID.
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
- ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"), identifier);
+ ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator
+ .createObjectIdentity(identifier, rs.getString("class"));
Acl parentAcl = null;
long parentAclId = rs.getLong("parent_object");
diff --git a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java
index 935466f5d1d..e499577388c 100644
--- a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java
+++ b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java
@@ -31,11 +31,12 @@
import org.springframework.core.convert.ConversionService;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.security.acls.domain.ObjectIdentityImpl;
+import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
+import org.springframework.security.acls.model.ObjectIdentityGenerator;
import org.springframework.security.acls.model.Sid;
import org.springframework.util.Assert;
@@ -81,6 +82,8 @@ public class JdbcAclService implements AclService {
private AclClassIdUtils aclClassIdUtils;
+ private ObjectIdentityGenerator objectIdentityGenerator;
+
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
this(new JdbcTemplate(dataSource), lookupStrategy);
}
@@ -91,6 +94,7 @@ public JdbcAclService(JdbcOperations jdbcOperations, LookupStrategy lookupStrate
this.jdbcOperations = jdbcOperations;
this.lookupStrategy = lookupStrategy;
this.aclClassIdUtils = new AclClassIdUtils();
+ this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
}
@Override
@@ -105,7 +109,7 @@ private ObjectIdentity mapObjectIdentityRow(ResultSet rs) throws SQLException {
String javaType = rs.getString("class");
Serializable identifier = (Serializable) rs.getObject("obj_id");
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
- return new ObjectIdentityImpl(javaType, identifier);
+ return this.objectIdentityGenerator.createObjectIdentity(identifier, javaType);
}
@Override
@@ -165,6 +169,11 @@ public void setConversionService(ConversionService conversionService) {
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
}
+ public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
+ Assert.notNull(objectIdentityGenerator, "objectIdentityGenerator cannot be null");
+ this.objectIdentityGenerator = objectIdentityGenerator;
+ }
+
protected boolean isAclClassIdSupported() {
return this.aclClassIdSupported;
}
diff --git a/acl/src/test/java/org/springframework/security/acls/jdbc/AbstractBasicLookupStrategyTests.java b/acl/src/test/java/org/springframework/security/acls/jdbc/AbstractBasicLookupStrategyTests.java
index 4a6b1d695f6..4ad369dc4be 100644
--- a/acl/src/test/java/org/springframework/security/acls/jdbc/AbstractBasicLookupStrategyTests.java
+++ b/acl/src/test/java/org/springframework/security/acls/jdbc/AbstractBasicLookupStrategyTests.java
@@ -16,6 +16,7 @@
package org.springframework.security.acls.jdbc;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -23,15 +24,15 @@
import javax.sql.DataSource;
-import net.sf.ehcache.Cache;
-import net.sf.ehcache.CacheManager;
-import net.sf.ehcache.Ehcache;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.acls.TargetObject;
import org.springframework.security.acls.TargetObjectWithUUID;
@@ -41,10 +42,10 @@
import org.springframework.security.acls.domain.ConsoleAuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
-import org.springframework.security.acls.domain.EhCacheBasedAclCache;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
+import org.springframework.security.acls.domain.SpringCacheBasedAclCache;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AuditableAccessControlEntry;
import org.springframework.security.acls.model.MutableAcl;
@@ -55,6 +56,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
/**
* Tests {@link BasicLookupStrategy}
@@ -75,7 +78,7 @@ public abstract class AbstractBasicLookupStrategyTests {
private BasicLookupStrategy strategy;
- private static CacheManager cacheManager;
+ private static CacheManagerMock cacheManager;
public abstract JdbcTemplate getJdbcTemplate();
@@ -83,14 +86,13 @@ public abstract class AbstractBasicLookupStrategyTests {
@BeforeAll
public static void initCacheManaer() {
- cacheManager = CacheManager.create();
- cacheManager.addCache(new Cache("basiclookuptestcache", 500, false, false, 30, 30));
+ cacheManager = new CacheManagerMock();
+ cacheManager.addCache("basiclookuptestcache");
}
@AfterAll
public static void shutdownCacheManager() {
- cacheManager.removalAll();
- cacheManager.shutdown();
+ cacheManager.clear();
}
@BeforeEach
@@ -118,11 +120,17 @@ protected AclAuthorizationStrategy aclAuthStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
}
- protected EhCacheBasedAclCache aclCache() {
- return new EhCacheBasedAclCache(getCache(), new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
+ protected SpringCacheBasedAclCache aclCache() {
+ return new SpringCacheBasedAclCache(getCache(), new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
}
+ protected Cache getCache() {
+ Cache cache = cacheManager.getCacheManager().getCache("basiclookuptestcache");
+ cache.clear();
+ return cache;
+ }
+
@AfterEach
public void emptyDatabase() {
String query = "DELETE FROM acl_entry;" + "DELETE FROM acl_object_identity WHERE ID = 9;"
@@ -134,12 +142,6 @@ public void emptyDatabase() {
getJdbcTemplate().execute(query);
}
- protected Ehcache getCache() {
- Ehcache cache = cacheManager.getCache("basiclookuptestcache");
- cache.removeAll();
- return cache;
- }
-
@Test
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, 100L);
@@ -318,4 +320,41 @@ public void testCreateGrantedAuthority() {
assertThat(((GrantedAuthoritySid) result).getGrantedAuthority()).isEqualTo("sid");
}
+ @Test
+ public void setObjectIdentityGeneratorWhenNullThenThrowsIllegalArgumentException() {
+ // @formatter:off
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> this.strategy.setObjectIdentityGenerator(null))
+ .withMessage("objectIdentityGenerator cannot be null");
+ // @formatter:on
+ }
+
+ private static final class CacheManagerMock {
+
+ private final List cacheNames;
+
+ private final CacheManager cacheManager;
+
+ private CacheManagerMock() {
+ this.cacheNames = new ArrayList<>();
+ this.cacheManager = mock(CacheManager.class);
+ given(this.cacheManager.getCacheNames()).willReturn(this.cacheNames);
+ }
+
+ private CacheManager getCacheManager() {
+ return this.cacheManager;
+ }
+
+ private void addCache(String name) {
+ this.cacheNames.add(name);
+ Cache cache = new ConcurrentMapCache(name);
+ given(this.cacheManager.getCache(name)).willReturn(cache);
+ }
+
+ private void clear() {
+ this.cacheNames.clear();
+ }
+
+ }
+
}
diff --git a/acl/src/test/java/org/springframework/security/acls/jdbc/EhCacheBasedAclCacheTests.java b/acl/src/test/java/org/springframework/security/acls/jdbc/EhCacheBasedAclCacheTests.java
deleted file mode 100644
index 35545abae26..00000000000
--- a/acl/src/test/java/org/springframework/security/acls/jdbc/EhCacheBasedAclCacheTests.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright 2002-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.acls.jdbc;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.util.List;
-
-import net.sf.ehcache.Ehcache;
-import net.sf.ehcache.Element;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import org.springframework.security.acls.domain.AclAuthorizationStrategy;
-import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
-import org.springframework.security.acls.domain.AclImpl;
-import org.springframework.security.acls.domain.ConsoleAuditLogger;
-import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
-import org.springframework.security.acls.domain.EhCacheBasedAclCache;
-import org.springframework.security.acls.domain.ObjectIdentityImpl;
-import org.springframework.security.acls.model.MutableAcl;
-import org.springframework.security.acls.model.ObjectIdentity;
-import org.springframework.security.authentication.TestingAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.util.FieldUtils;
-import org.springframework.test.util.ReflectionTestUtils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-/**
- * Tests {@link EhCacheBasedAclCache}
- *
- * @author Andrei Stefan
- */
-@ExtendWith(MockitoExtension.class)
-public class EhCacheBasedAclCacheTests {
-
- private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
-
- @Mock
- private Ehcache cache;
-
- @Captor
- private ArgumentCaptor element;
-
- private EhCacheBasedAclCache myCache;
-
- private MutableAcl acl;
-
- @BeforeEach
- public void setup() {
- this.myCache = new EhCacheBasedAclCache(this.cache,
- new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
- new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
- ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, 100L);
- AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
- new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
- new SimpleGrantedAuthority("ROLE_GENERAL"));
- this.acl = new AclImpl(identity, 1L, aclAuthorizationStrategy, new ConsoleAuditLogger());
- }
-
- @AfterEach
- public void cleanup() {
- SecurityContextHolder.clearContext();
- }
-
- @Test
- public void constructorRejectsNullParameters() {
- assertThatIllegalArgumentException().isThrownBy(
- () -> new EhCacheBasedAclCache(null, new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
- new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER"))));
- }
-
- @Test
- public void methodsRejectNullParameters() {
- assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.evictFromCache((Serializable) null));
- assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.evictFromCache((ObjectIdentity) null));
- assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.getFromCache((Serializable) null));
- assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.getFromCache((ObjectIdentity) null));
- assertThatIllegalArgumentException().isThrownBy(() -> this.myCache.putInCache(null));
- }
-
- // SEC-527
- @Test
- public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
- // Serialization test
- File file = File.createTempFile("SEC_TEST", ".object");
- FileOutputStream fos = new FileOutputStream(file);
- ObjectOutputStream oos = new ObjectOutputStream(fos);
- oos.writeObject(this.acl);
- oos.close();
- FileInputStream fis = new FileInputStream(file);
- ObjectInputStream ois = new ObjectInputStream(fis);
- MutableAcl retrieved = (MutableAcl) ois.readObject();
- ois.close();
- assertThat(retrieved).isEqualTo(this.acl);
- Object retrieved1 = FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", retrieved);
- assertThat(retrieved1).isNull();
- Object retrieved2 = FieldUtils.getProtectedFieldValue("permissionGrantingStrategy", retrieved);
- assertThat(retrieved2).isNull();
- }
-
- @Test
- public void clearCache() {
- this.myCache.clearCache();
- verify(this.cache).removeAll();
- }
-
- @Test
- public void putInCache() {
- this.myCache.putInCache(this.acl);
- verify(this.cache, times(2)).put(this.element.capture());
- assertThat(this.element.getValue().getKey()).isEqualTo(this.acl.getId());
- assertThat(this.element.getValue().getObjectValue()).isEqualTo(this.acl);
- assertThat(this.element.getAllValues().get(0).getKey()).isEqualTo(this.acl.getObjectIdentity());
- assertThat(this.element.getAllValues().get(0).getObjectValue()).isEqualTo(this.acl);
- }
-
- @Test
- public void putInCacheAclWithParent() {
- Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
- auth.setAuthenticated(true);
- SecurityContextHolder.getContext().setAuthentication(auth);
- ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, 2L);
- AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
- new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
- new SimpleGrantedAuthority("ROLE_GENERAL"));
- MutableAcl parentAcl = new AclImpl(identityParent, 2L, aclAuthorizationStrategy, new ConsoleAuditLogger());
- this.acl.setParent(parentAcl);
- this.myCache.putInCache(this.acl);
- verify(this.cache, times(4)).put(this.element.capture());
- List allValues = this.element.getAllValues();
- assertThat(allValues.get(0).getKey()).isEqualTo(parentAcl.getObjectIdentity());
- assertThat(allValues.get(0).getObjectValue()).isEqualTo(parentAcl);
- assertThat(allValues.get(1).getKey()).isEqualTo(parentAcl.getId());
- assertThat(allValues.get(1).getObjectValue()).isEqualTo(parentAcl);
- assertThat(allValues.get(2).getKey()).isEqualTo(this.acl.getObjectIdentity());
- assertThat(allValues.get(2).getObjectValue()).isEqualTo(this.acl);
- assertThat(allValues.get(3).getKey()).isEqualTo(this.acl.getId());
- assertThat(allValues.get(3).getObjectValue()).isEqualTo(this.acl);
- }
-
- @Test
- public void getFromCacheSerializable() {
- given(this.cache.get(this.acl.getId())).willReturn(new Element(this.acl.getId(), this.acl));
- assertThat(this.myCache.getFromCache(this.acl.getId())).isEqualTo(this.acl);
- }
-
- @Test
- public void getFromCacheSerializablePopulatesTransient() {
- given(this.cache.get(this.acl.getId())).willReturn(new Element(this.acl.getId(), this.acl));
- this.myCache.putInCache(this.acl);
- ReflectionTestUtils.setField(this.acl, "permissionGrantingStrategy", null);
- ReflectionTestUtils.setField(this.acl, "aclAuthorizationStrategy", null);
- MutableAcl fromCache = this.myCache.getFromCache(this.acl.getId());
- assertThat(ReflectionTestUtils.getField(fromCache, "aclAuthorizationStrategy")).isNotNull();
- assertThat(ReflectionTestUtils.getField(fromCache, "permissionGrantingStrategy")).isNotNull();
- }
-
- @Test
- public void getFromCacheObjectIdentity() {
- given(this.cache.get(this.acl.getId())).willReturn(new Element(this.acl.getId(), this.acl));
- assertThat(this.myCache.getFromCache(this.acl.getId())).isEqualTo(this.acl);
- }
-
- @Test
- public void getFromCacheObjectIdentityPopulatesTransient() {
- given(this.cache.get(this.acl.getObjectIdentity())).willReturn(new Element(this.acl.getId(), this.acl));
- this.myCache.putInCache(this.acl);
- ReflectionTestUtils.setField(this.acl, "permissionGrantingStrategy", null);
- ReflectionTestUtils.setField(this.acl, "aclAuthorizationStrategy", null);
- MutableAcl fromCache = this.myCache.getFromCache(this.acl.getObjectIdentity());
- assertThat(ReflectionTestUtils.getField(fromCache, "aclAuthorizationStrategy")).isNotNull();
- assertThat(ReflectionTestUtils.getField(fromCache, "permissionGrantingStrategy")).isNotNull();
- }
-
- @Test
- public void evictCacheSerializable() {
- given(this.cache.get(this.acl.getObjectIdentity())).willReturn(new Element(this.acl.getId(), this.acl));
- this.myCache.evictFromCache(this.acl.getObjectIdentity());
- verify(this.cache).remove(this.acl.getId());
- verify(this.cache).remove(this.acl.getObjectIdentity());
- }
-
- @Test
- public void evictCacheObjectIdentity() {
- given(this.cache.get(this.acl.getId())).willReturn(new Element(this.acl.getId(), this.acl));
- this.myCache.evictFromCache(this.acl.getId());
- verify(this.cache).remove(this.acl.getId());
- verify(this.cache).remove(this.acl.getObjectIdentity());
- }
-
-}
diff --git a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java b/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java
index 903fd3264ce..cd91ae17453 100644
--- a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java
+++ b/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java
@@ -45,6 +45,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.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
@@ -170,6 +171,26 @@ public void findChildrenOfIdTypeUUID() {
.isEqualTo(UUID.fromString("25d93b3f-c3aa-4814-9d5e-c7c96ced7762"));
}
+ @Test
+ public void setObjectIdentityGeneratorWhenNullThenThrowsIllegalArgumentException() {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> this.aclServiceIntegration.setObjectIdentityGenerator(null))
+ .withMessage("objectIdentityGenerator cannot be null");
+ }
+
+ @Test
+ public void findChildrenWhenObjectIdentityGeneratorSetThenUsed() {
+ this.aclServiceIntegration
+ .setObjectIdentityGenerator((id, type) -> new ObjectIdentityImpl(type, "prefix:" + id));
+
+ ObjectIdentity objectIdentity = new ObjectIdentityImpl("location", "US");
+ this.aclServiceIntegration.setAclClassIdSupported(true);
+ List objectIdentities = this.aclServiceIntegration.findChildren(objectIdentity);
+ assertThat(objectIdentities.size()).isEqualTo(1);
+ assertThat(objectIdentities.get(0).getType()).isEqualTo("location");
+ assertThat(objectIdentities.get(0).getIdentifier()).isEqualTo("prefix:US-PAL");
+ }
+
class MockLongIdDomainObject {
private Object id;
diff --git a/acl/src/test/resources/jdbcMutableAclServiceTests-context.xml b/acl/src/test/resources/jdbcMutableAclServiceTests-context.xml
index 457c183d569..d23a727141c 100644
--- a/acl/src/test/resources/jdbcMutableAclServiceTests-context.xml
+++ b/acl/src/test/resources/jdbcMutableAclServiceTests-context.xml
@@ -13,16 +13,10 @@
-
+
-
-
-
-
-
-
-
-
+
+
diff --git a/aspects/spring-security-aspects.gradle b/aspects/spring-security-aspects.gradle
index 3a58595619f..eb43bb87576 100644
--- a/aspects/spring-security-aspects.gradle
+++ b/aspects/spring-security-aspects.gradle
@@ -1,6 +1,15 @@
apply plugin: 'io.spring.convention.spring-module'
apply plugin: 'io.freefair.aspectj'
+compileAspectj {
+ sourceCompatibility "17"
+ targetCompatibility "17"
+}
+compileTestAspectj {
+ sourceCompatibility "17"
+ targetCompatibility "17"
+}
+
dependencies {
management platform(project(":spring-security-dependencies"))
api "org.aspectj:aspectjrt"
@@ -27,7 +36,3 @@ sourceSets.test.aspectj.srcDir "src/test/java"
sourceSets.test.java.srcDirs = files()
compileAspectj.ajcOptions.outxmlfile = "META-INF/aop.xml"
-
-aspectj {
- version = aspectjVersion
-}
diff --git a/build.gradle b/build.gradle
index 20f17eab4f7..17d42b1b817 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ 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.2.0"
+ classpath "io.freefair.gradle:aspectj-plugin:6.3.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "com.netflix.nebula:nebula-project-plugin:8.2.0"
}
@@ -22,6 +22,7 @@ apply plugin: 'org.springframework.security.update-dependencies'
apply plugin: 'org.springframework.security.sagan'
apply plugin: 'org.springframework.github.milestone'
apply plugin: 'org.springframework.github.changelog'
+apply plugin: 'org.springframework.github.release'
group = 'org.springframework.security'
description = 'Spring Security'
@@ -46,6 +47,13 @@ tasks.named("gitHubCheckMilestoneHasNoOpenIssues") {
}
}
+tasks.named("createGitHubRelease") {
+ repository {
+ owner = "spring-projects"
+ name = "spring-security"
+ }
+}
+
tasks.named("updateDependencies") {
// we aren't Gradle 7 compatible yet
checkForGradleUpdate = false
@@ -100,7 +108,7 @@ updateDependenciesSettings {
subprojects {
plugins.withType(JavaPlugin) {
- project.sourceCompatibility='1.8'
+ project.sourceCompatibility=JavaVersion.VERSION_17
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index 18001d9e6a3..bd715609a60 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -5,11 +5,9 @@ plugins {
id 'com.apollographql.apollo' version '2.4.5'
}
-
-sourceCompatibility = 1.8
+sourceCompatibility = JavaVersion.VERSION_11
repositories {
- jcenter()
gradlePluginPortal()
mavenCentral()
maven { url 'https://repo.spring.io/plugins-release/' }
@@ -56,6 +54,10 @@ gradlePlugin {
id = "org.springframework.github.changelog"
implementationClass = "org.springframework.gradle.github.changelog.GitHubChangelogPlugin"
}
+ githubRelease {
+ id = "org.springframework.github.release"
+ implementationClass = "org.springframework.gradle.github.release.GitHubReleasePlugin"
+ }
s101 {
id = "s101"
implementationClass = "s101.S101Plugin"
diff --git a/buildSrc/gradle/wrapper/gradle-wrapper.jar b/buildSrc/gradle/wrapper/gradle-wrapper.jar
index e708b1c023e..7454180f2ae 100644
Binary files a/buildSrc/gradle/wrapper/gradle-wrapper.jar and b/buildSrc/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/buildSrc/gradle/wrapper/gradle-wrapper.properties b/buildSrc/gradle/wrapper/gradle-wrapper.properties
index ffed3a254e9..e750102e092 100644
--- a/buildSrc/gradle/wrapper/gradle-wrapper.properties
+++ b/buildSrc/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/DocsPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/DocsPlugin.groovy
index d0a64ab85bb..c62fef79b1c 100644
--- a/buildSrc/src/main/groovy/io/spring/gradle/convention/DocsPlugin.groovy
+++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/DocsPlugin.groovy
@@ -25,7 +25,7 @@ public class DocsPlugin implements Plugin {
group = 'Distribution'
archiveBaseName = project.rootProject.name
archiveClassifier = 'docs'
- description = "Builds -${classifier} archive containing all " +
+ description = "Builds -${archiveClassifier.get()} archive containing all " +
"Docs for deployment at docs.spring.io"
from(project.tasks.api.outputs) {
diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/JacocoPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/JacocoPlugin.groovy
index 900cf9f1442..8f558eabbe3 100644
--- a/buildSrc/src/main/groovy/io/spring/gradle/convention/JacocoPlugin.groovy
+++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/JacocoPlugin.groovy
@@ -34,7 +34,7 @@ class JacocoPlugin implements Plugin {
project.tasks.check.dependsOn project.tasks.jacocoTestReport
project.jacoco {
- toolVersion = '0.8.2'
+ toolVersion = '0.8.7'
}
}
}
diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy
index c2420814290..407163d82a0 100644
--- a/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy
+++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy
@@ -35,11 +35,6 @@ class RepositoryConventionPlugin implements Plugin {
mavenLocal()
}
mavenCentral()
- jcenter() {
- content {
- includeGroup "org.gretty"
- }
- }
if (isSnapshot) {
maven {
name = 'artifactory-snapshot'
diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/RepositoryRef.java b/buildSrc/src/main/java/org/springframework/gradle/github/RepositoryRef.java
similarity index 93%
rename from buildSrc/src/main/java/org/springframework/gradle/github/milestones/RepositoryRef.java
rename to buildSrc/src/main/java/org/springframework/gradle/github/RepositoryRef.java
index 70eec3b1505..e570a47e902 100644
--- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/RepositoryRef.java
+++ b/buildSrc/src/main/java/org/springframework/gradle/github/RepositoryRef.java
@@ -1,10 +1,11 @@
-package org.springframework.gradle.github.milestones;
+package org.springframework.gradle.github;
+
public class RepositoryRef {
private String owner;
private String name;
- RepositoryRef() {
+ public RepositoryRef() {
}
public RepositoryRef(String owner, String name) {
@@ -62,4 +63,3 @@ public RepositoryRef build() {
}
}
}
-
diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/changelog/GitHubChangelogPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/github/changelog/GitHubChangelogPlugin.java
index 2000e1a378c..0eab3d80068 100644
--- a/buildSrc/src/main/java/org/springframework/gradle/github/changelog/GitHubChangelogPlugin.java
+++ b/buildSrc/src/main/java/org/springframework/gradle/github/changelog/GitHubChangelogPlugin.java
@@ -16,6 +16,9 @@
package org.springframework.gradle.github.changelog;
+import java.io.File;
+import java.nio.file.Paths;
+
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
@@ -28,12 +31,10 @@
import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout;
import org.gradle.api.tasks.JavaExec;
-import java.io.File;
-import java.nio.file.Paths;
-
public class GitHubChangelogPlugin implements Plugin {
public static final String CHANGELOG_GENERATOR_CONFIGURATION_NAME = "changelogGenerator";
+ public static final String RELEASE_NOTES_PATH = "changelog/release-notes.md";
@Override
public void apply(Project project) {
@@ -42,7 +43,7 @@ public void apply(Project project) {
project.getTasks().register("generateChangelog", JavaExec.class, new Action() {
@Override
public void execute(JavaExec generateChangelog) {
- File outputFile = project.file(Paths.get(project.getBuildDir().getPath(), "changelog/release-notes.md"));
+ File outputFile = project.file(Paths.get(project.getBuildDir().getPath(), RELEASE_NOTES_PATH));
outputFile.getParentFile().mkdirs();
generateChangelog.setGroup("Release");
generateChangelog.setDescription("Generates the changelog");
diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java
index 31f1274adb4..fd3c0d817bb 100644
--- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java
+++ b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java
@@ -16,6 +16,9 @@
package org.springframework.gradle.github.milestones;
+import java.io.IOException;
+import java.util.List;
+
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import okhttp3.Interceptor;
@@ -23,8 +26,7 @@
import okhttp3.Request;
import okhttp3.Response;
-import java.io.IOException;
-import java.util.List;
+import org.springframework.gradle.github.RepositoryRef;
public class GitHubMilestoneApi {
private String baseUrl = "https://api.github.com";
diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java
index de846378f7a..40b026c8045 100644
--- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java
+++ b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java
@@ -21,6 +21,8 @@
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.TaskAction;
+import org.springframework.gradle.github.RepositoryRef;
+
public class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask {
@Input
private RepositoryRef repository = new RepositoryRef();
diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java
index 527b7676133..81663f25611 100644
--- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java
+++ b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java
@@ -29,7 +29,7 @@ public void execute(GitHubMilestoneHasNoOpenIssuesTask githubCheckMilestoneHasNo
githubCheckMilestoneHasNoOpenIssues.setGroup("Release");
githubCheckMilestoneHasNoOpenIssues.setDescription("Checks if there are any open issues for the specified repository and milestone");
githubCheckMilestoneHasNoOpenIssues.setMilestoneTitle((String) project.findProperty("nextVersion"));
- if (project.hasProperty("githubAccessToken")) {
+ if (project.hasProperty("gitHubAccessToken")) {
githubCheckMilestoneHasNoOpenIssues.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
}
}
diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/CreateGitHubReleaseTask.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/CreateGitHubReleaseTask.java
new file mode 100644
index 00000000000..65c8b687be0
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/gradle/github/release/CreateGitHubReleaseTask.java
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ * 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.release;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.gradle.api.Action;
+import org.gradle.api.DefaultTask;
+import org.gradle.api.Project;
+import org.gradle.api.tasks.Input;
+import org.gradle.api.tasks.Optional;
+import org.gradle.api.tasks.TaskAction;
+
+import org.springframework.gradle.github.RepositoryRef;
+import org.springframework.gradle.github.changelog.GitHubChangelogPlugin;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class CreateGitHubReleaseTask extends DefaultTask {
+ @Input
+ private RepositoryRef repository = new RepositoryRef();
+
+ @Input @Optional
+ private String gitHubAccessToken;
+
+ @Input
+ private String version;
+
+ @Input @Optional
+ private String branch = "main";
+
+ @Input
+ private boolean createRelease = false;
+
+ @TaskAction
+ public void createGitHubRelease() {
+ String body = readReleaseNotes();
+ Release release = Release.tag(this.version)
+ .commit(this.branch)
+ .name(this.version)
+ .body(body)
+ .preRelease(this.version.contains("-"))
+ .build();
+
+ System.out.printf("%sCreating GitHub release for %s/%s@%s\n",
+ this.createRelease ? "" : "[DRY RUN] ",
+ this.repository.getOwner(),
+ this.repository.getName(),
+ this.version
+ );
+ System.out.printf(" Release Notes:\n\n----\n%s\n----\n\n", body.trim());
+
+ if (this.createRelease) {
+ GitHubReleaseApi github = new GitHubReleaseApi(this.gitHubAccessToken);
+ github.publishRelease(this.repository, release);
+ }
+ }
+
+ private String readReleaseNotes() {
+ Project project = getProject();
+ File inputFile = project.file(Paths.get(project.getBuildDir().getPath(), GitHubChangelogPlugin.RELEASE_NOTES_PATH));
+ try {
+ return Files.readString(inputFile.toPath());
+ } catch (IOException ex) {
+ throw new RuntimeException("Unable to read release notes from " + inputFile, ex);
+ }
+ }
+
+ public RepositoryRef getRepository() {
+ return repository;
+ }
+
+ public void repository(Action repository) {
+ repository.execute(this.repository);
+ }
+
+ public void setRepository(RepositoryRef repository) {
+ this.repository = repository;
+ }
+
+ public String getGitHubAccessToken() {
+ return gitHubAccessToken;
+ }
+
+ public void setGitHubAccessToken(String gitHubAccessToken) {
+ this.gitHubAccessToken = gitHubAccessToken;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getBranch() {
+ return branch;
+ }
+
+ public void setBranch(String branch) {
+ this.branch = branch;
+ }
+
+ public boolean isCreateRelease() {
+ return createRelease;
+ }
+
+ public void setCreateRelease(boolean createRelease) {
+ this.createRelease = createRelease;
+ }
+}
diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleaseApi.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleaseApi.java
new file mode 100644
index 00000000000..65238d0b821
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleaseApi.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ * 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.release;
+
+import java.io.IOException;
+
+import com.google.gson.Gson;
+import okhttp3.Interceptor;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+import org.springframework.gradle.github.RepositoryRef;
+
+/**
+ * Manage GitHub releases.
+ *
+ * @author Steve Riesenberg
+ */
+public class GitHubReleaseApi {
+ private String baseUrl = "https://api.github.com";
+
+ private final OkHttpClient httpClient;
+ private Gson gson = new Gson();
+
+ public GitHubReleaseApi(String gitHubAccessToken) {
+ this.httpClient = new OkHttpClient.Builder()
+ .addInterceptor(new AuthorizationInterceptor(gitHubAccessToken))
+ .build();
+ }
+
+ public void setBaseUrl(String baseUrl) {
+ this.baseUrl = baseUrl;
+ }
+
+ /**
+ * Publish a release with no binary attachments.
+ *
+ * @param repository The repository owner/name
+ * @param release The contents of the release
+ */
+ public void publishRelease(RepositoryRef repository, Release release) {
+ String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/releases";
+ String json = this.gson.toJson(release);
+ RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
+ Request request = new Request.Builder().url(url).post(body).build();
+ try {
+ Response response = this.httpClient.newCall(request).execute();
+ if (!response.isSuccessful()) {
+ throw new RuntimeException(String.format("Could not create release %s for repository %s/%s. Got response %s",
+ release.getName(), repository.getOwner(), repository.getName(), response));
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException(String.format("Could not create release %s for repository %s/%s",
+ release.getName(), repository.getOwner(), repository.getName()), 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);
+ }
+ }
+}
diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleasePlugin.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleasePlugin.java
new file mode 100644
index 00000000000..ae2c44a7694
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleasePlugin.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ * 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.release;
+
+import groovy.lang.MissingPropertyException;
+import org.gradle.api.Action;
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class GitHubReleasePlugin implements Plugin {
+ @Override
+ public void apply(Project project) {
+ project.getTasks().register("createGitHubRelease", CreateGitHubReleaseTask.class, new Action() {
+ @Override
+ public void execute(CreateGitHubReleaseTask createGitHubRelease) {
+ createGitHubRelease.setGroup("Release");
+ createGitHubRelease.setDescription("Create a github release");
+ createGitHubRelease.dependsOn("generateChangelog");
+
+ createGitHubRelease.setCreateRelease("true".equals(project.findProperty("createRelease")));
+ createGitHubRelease.setVersion((String) project.findProperty("nextVersion"));
+ if (project.hasProperty("branch")) {
+ createGitHubRelease.setBranch((String) project.findProperty("branch"));
+ }
+ createGitHubRelease.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
+ if (createGitHubRelease.isCreateRelease() && createGitHubRelease.getGitHubAccessToken() == null) {
+ throw new MissingPropertyException("Please provide an access token with -PgitHubAccessToken=...");
+ }
+ }
+ });
+ }
+}
diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/Release.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/Release.java
new file mode 100644
index 00000000000..6dec2ceb796
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/gradle/github/release/Release.java
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ * 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.release;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class Release {
+ @SerializedName("tag_name")
+ private final String tag;
+
+ @SerializedName("target_commitish")
+ private final String commit;
+
+ @SerializedName("name")
+ private final String name;
+
+ @SerializedName("body")
+ private final String body;
+
+ @SerializedName("draft")
+ private final boolean draft;
+
+ @SerializedName("prerelease")
+ private final boolean preRelease;
+
+ @SerializedName("generate_release_notes")
+ private final boolean generateReleaseNotes;
+
+ private Release(String tag, String commit, String name, String body, boolean draft, boolean preRelease, boolean generateReleaseNotes) {
+ this.tag = tag;
+ this.commit = commit;
+ this.name = name;
+ this.body = body;
+ this.draft = draft;
+ this.preRelease = preRelease;
+ this.generateReleaseNotes = generateReleaseNotes;
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ public String getCommit() {
+ return commit;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public boolean isDraft() {
+ return draft;
+ }
+
+ public boolean isPreRelease() {
+ return preRelease;
+ }
+
+ public boolean isGenerateReleaseNotes() {
+ return generateReleaseNotes;
+ }
+
+ @Override
+ public String toString() {
+ return "Release{" +
+ "tag='" + tag + '\'' +
+ ", commit='" + commit + '\'' +
+ ", name='" + name + '\'' +
+ ", body='" + body + '\'' +
+ ", draft=" + draft +
+ ", preRelease=" + preRelease +
+ ", generateReleaseNotes=" + generateReleaseNotes +
+ '}';
+ }
+
+ public static Builder tag(String tag) {
+ return new Builder().tag(tag);
+ }
+
+ public static Builder commit(String commit) {
+ return new Builder().commit(commit);
+ }
+
+ public static final class Builder {
+ private String tag;
+ private String commit;
+ private String name;
+ private String body;
+ private boolean draft;
+ private boolean preRelease;
+ private boolean generateReleaseNotes;
+
+ private Builder() {
+ }
+
+ public Builder tag(String tag) {
+ this.tag = tag;
+ return this;
+ }
+
+ public Builder commit(String commit) {
+ this.commit = commit;
+ return this;
+ }
+
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder body(String body) {
+ this.body = body;
+ return this;
+ }
+
+ public Builder draft(boolean draft) {
+ this.draft = draft;
+ return this;
+ }
+
+ public Builder preRelease(boolean preRelease) {
+ this.preRelease = preRelease;
+ return this;
+ }
+
+ public Builder generateReleaseNotes(boolean generateReleaseNotes) {
+ this.generateReleaseNotes = generateReleaseNotes;
+ return this;
+ }
+
+ public Release build() {
+ return new Release(tag, commit, name, body, draft, preRelease, generateReleaseNotes);
+ }
+ }
+}
diff --git a/buildSrc/src/main/java/s101/S101Configurer.java b/buildSrc/src/main/java/s101/S101Configurer.java
index 414e4885358..b3b74391366 100644
--- a/buildSrc/src/main/java/s101/S101Configurer.java
+++ b/buildSrc/src/main/java/s101/S101Configurer.java
@@ -161,7 +161,7 @@ private boolean deleteDirectory(File directoryToBeDeleted) {
}
private String installBuildTool(File installationDirectory, File configurationDirectory) {
- String source = "https://structure101.com/binaries/v6";
+ String source = "https://structure101.com/binaries/19159";
try (final WebClient webClient = new WebClient()) {
HtmlPage page = webClient.getPage(source);
for (HtmlAnchor anchor : page.getAnchors()) {
diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginITest.java b/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginITest.java
index 681d5c49831..e77f341786a 100644
--- a/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginITest.java
+++ b/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginITest.java
@@ -5,6 +5,7 @@
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -28,7 +29,7 @@ public void multiModuleApi() throws Exception {
.build();
assertThat(result.task(":api").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
File allClasses = new File(testKit.getRootDir(), "build/api/allclasses-noframe.html");
- File index = new File(testKit.getRootDir(), "build/api/allclasses.html");
+ File index = new File(testKit.getRootDir(), "build/api/allclasses-index.html");
File listing = allClasses.exists() ? allClasses : index;
String listingText = FileUtils.readFileToString(listing);
assertThat(listingText).contains("sample/Api.html");
diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/RepositoryConventionPluginTests.java b/buildSrc/src/test/java/io/spring/gradle/convention/RepositoryConventionPluginTests.java
index 2bad49c8a3a..f1048dbbab6 100644
--- a/buildSrc/src/test/java/io/spring/gradle/convention/RepositoryConventionPluginTests.java
+++ b/buildSrc/src/test/java/io/spring/gradle/convention/RepositoryConventionPluginTests.java
@@ -107,7 +107,7 @@ public void applyWhenIsReleaseWithForceLocalThenShouldIncludeReleaseAndLocalRepo
this.project.getPluginManager().apply(RepositoryConventionPlugin.class);
RepositoryHandler repositories = this.project.getRepositories();
- assertThat(repositories).hasSize(5);
+ assertThat(repositories).hasSize(4);
assertThat((repositories.get(0)).getName()).isEqualTo("MavenLocal");
}
@@ -119,39 +119,33 @@ public void applyWhenIsReleaseWithForceMilestoneAndLocalThenShouldIncludeMilesto
this.project.getPluginManager().apply(RepositoryConventionPlugin.class);
RepositoryHandler repositories = this.project.getRepositories();
- assertThat(repositories).hasSize(6);
+ assertThat(repositories).hasSize(5);
assertThat((repositories.get(0)).getName()).isEqualTo("MavenLocal");
}
private void assertSnapshotRepository(RepositoryHandler repositories) {
- assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(6);
+ assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(5);
assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString())
.isEqualTo("https://repo.maven.apache.org/maven2/");
assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString())
- .isEqualTo("https://jcenter.bintray.com/");
- assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
.isEqualTo("https://repo.spring.io/snapshot/");
- assertThat(((MavenArtifactRepository) repositories.get(3)).getUrl().toString())
+ assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
.isEqualTo("https://repo.spring.io/milestone/");
}
private void assertMilestoneRepository(RepositoryHandler repositories) {
- assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(5);
+ assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(4);
assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString())
.isEqualTo("https://repo.maven.apache.org/maven2/");
assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString())
- .isEqualTo("https://jcenter.bintray.com/");
- assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
.isEqualTo("https://repo.spring.io/milestone/");
}
private void assertReleaseRepository(RepositoryHandler repositories) {
- assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(4);
+ assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(3);
assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString())
.isEqualTo("https://repo.maven.apache.org/maven2/");
assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString())
- .isEqualTo("https://jcenter.bintray.com/");
- assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString())
.isEqualTo("https://repo.spring.io/release/");
}
diff --git a/buildSrc/src/test/java/io/spring/gradle/github/milestones/GitHubMilestoneApiTests.java b/buildSrc/src/test/java/io/spring/gradle/github/milestones/GitHubMilestoneApiTests.java
index 183cf09d5ab..b9b0764ee53 100644
--- a/buildSrc/src/test/java/io/spring/gradle/github/milestones/GitHubMilestoneApiTests.java
+++ b/buildSrc/src/test/java/io/spring/gradle/github/milestones/GitHubMilestoneApiTests.java
@@ -1,15 +1,16 @@
package io.spring.gradle.github.milestones;
+import java.util.concurrent.TimeUnit;
+
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.springframework.gradle.github.milestones.GitHubMilestoneApi;
-import org.springframework.gradle.github.milestones.RepositoryRef;
-import java.util.concurrent.TimeUnit;
+import org.springframework.gradle.github.RepositoryRef;
+import org.springframework.gradle.github.milestones.GitHubMilestoneApi;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
diff --git a/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java b/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java
index b4072c079eb..0a1a293ab04 100644
--- a/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java
+++ b/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java
@@ -1,5 +1,7 @@
package org.springframework.gradle.github.milestones;
+import java.util.concurrent.TimeUnit;
+
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
@@ -7,7 +9,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import java.util.concurrent.TimeUnit;
+import org.springframework.gradle.github.RepositoryRef;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
diff --git a/buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubReleaseApiTests.java b/buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubReleaseApiTests.java
new file mode 100644
index 00000000000..6ac79557222
--- /dev/null
+++ b/buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubReleaseApiTests.java
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ * 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.release;
+
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.junit.Test;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+
+import org.springframework.gradle.github.RepositoryRef;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class GitHubReleaseApiTests {
+ private GitHubReleaseApi github;
+
+ private RepositoryRef repository = new RepositoryRef("spring-projects", "spring-security");
+
+ private MockWebServer server;
+
+ private String baseUrl;
+
+ @BeforeEach
+ public void setup() throws Exception {
+ this.server = new MockWebServer();
+ this.server.start();
+ this.github = new GitHubReleaseApi("mock-oauth-token");
+ this.baseUrl = this.server.url("/api").toString();
+ this.github.setBaseUrl(this.baseUrl);
+ }
+
+ @AfterEach
+ public void cleanup() throws Exception {
+ this.server.shutdown();
+ }
+
+ @Test
+ public void publishReleaseWhenValidParametersThenSuccess() throws Exception {
+ String responseJson = "{\n" +
+ " \"url\": \"https://api.github.com/spring-projects/spring-security/releases/1\",\n" +
+ " \"html_url\": \"https://github.com/spring-projects/spring-security/releases/tags/v1.0.0\",\n" +
+ " \"assets_url\": \"https://api.github.com/spring-projects/spring-security/releases/1/assets\",\n" +
+ " \"upload_url\": \"https://uploads.github.com/spring-projects/spring-security/releases/1/assets{?name,label}\",\n" +
+ " \"tarball_url\": \"https://api.github.com/spring-projects/spring-security/tarball/v1.0.0\",\n" +
+ " \"zipball_url\": \"https://api.github.com/spring-projects/spring-security/zipball/v1.0.0\",\n" +
+ " \"discussion_url\": \"https://github.com/spring-projects/spring-security/discussions/90\",\n" +
+ " \"id\": 1,\n" +
+ " \"node_id\": \"MDc6UmVsZWFzZTE=\",\n" +
+ " \"tag_name\": \"v1.0.0\",\n" +
+ " \"target_commitish\": \"main\",\n" +
+ " \"name\": \"v1.0.0\",\n" +
+ " \"body\": \"Description of the release\",\n" +
+ " \"draft\": false,\n" +
+ " \"prerelease\": false,\n" +
+ " \"created_at\": \"2013-02-27T19:35:32Z\",\n" +
+ " \"published_at\": \"2013-02-27T19:35:32Z\",\n" +
+ " \"author\": {\n" +
+ " \"login\": \"sjohnr\",\n" +
+ " \"id\": 1,\n" +
+ " \"node_id\": \"MDQ6VXNlcjE=\",\n" +
+ " \"avatar_url\": \"https://github.com/images/avatar.gif\",\n" +
+ " \"gravatar_id\": \"\",\n" +
+ " \"url\": \"https://api.github.com/users/sjohnr\",\n" +
+ " \"html_url\": \"https://github.com/sjohnr\",\n" +
+ " \"followers_url\": \"https://api.github.com/users/sjohnr/followers\",\n" +
+ " \"following_url\": \"https://api.github.com/users/sjohnr/following{/other_user}\",\n" +
+ " \"gists_url\": \"https://api.github.com/users/sjohnr/gists{/gist_id}\",\n" +
+ " \"starred_url\": \"https://api.github.com/users/sjohnr/starred{/owner}{/repo}\",\n" +
+ " \"subscriptions_url\": \"https://api.github.com/users/sjohnr/subscriptions\",\n" +
+ " \"organizations_url\": \"https://api.github.com/users/sjohnr/orgs\",\n" +
+ " \"repos_url\": \"https://api.github.com/users/sjohnr/repos\",\n" +
+ " \"events_url\": \"https://api.github.com/users/sjohnr/events{/privacy}\",\n" +
+ " \"received_events_url\": \"https://api.github.com/users/sjohnr/received_events\",\n" +
+ " \"type\": \"User\",\n" +
+ " \"site_admin\": false\n" +
+ " },\n" +
+ " \"assets\": [\n" +
+ " {\n" +
+ " \"url\": \"https://api.github.com/spring-projects/spring-security/releases/assets/1\",\n" +
+ " \"browser_download_url\": \"https://github.com/spring-projects/spring-security/releases/download/v1.0.0/example.zip\",\n" +
+ " \"id\": 1,\n" +
+ " \"node_id\": \"MDEyOlJlbGVhc2VBc3NldDE=\",\n" +
+ " \"name\": \"example.zip\",\n" +
+ " \"label\": \"short description\",\n" +
+ " \"state\": \"uploaded\",\n" +
+ " \"content_type\": \"application/zip\",\n" +
+ " \"size\": 1024,\n" +
+ " \"download_count\": 42,\n" +
+ " \"created_at\": \"2013-02-27T19:35:32Z\",\n" +
+ " \"updated_at\": \"2013-02-27T19:35:32Z\",\n" +
+ " \"uploader\": {\n" +
+ " \"login\": \"sjohnr\",\n" +
+ " \"id\": 1,\n" +
+ " \"node_id\": \"MDQ6VXNlcjE=\",\n" +
+ " \"avatar_url\": \"https://github.com/images/avatar.gif\",\n" +
+ " \"gravatar_id\": \"\",\n" +
+ " \"url\": \"https://api.github.com/users/sjohnr\",\n" +
+ " \"html_url\": \"https://github.com/sjohnr\",\n" +
+ " \"followers_url\": \"https://api.github.com/users/sjohnr/followers\",\n" +
+ " \"following_url\": \"https://api.github.com/users/sjohnr/following{/other_user}\",\n" +
+ " \"gists_url\": \"https://api.github.com/users/sjohnr/gists{/gist_id}\",\n" +
+ " \"starred_url\": \"https://api.github.com/users/sjohnr/starred{/owner}{/repo}\",\n" +
+ " \"subscriptions_url\": \"https://api.github.com/users/sjohnr/subscriptions\",\n" +
+ " \"organizations_url\": \"https://api.github.com/users/sjohnr/orgs\",\n" +
+ " \"repos_url\": \"https://api.github.com/users/sjohnr/repos\",\n" +
+ " \"events_url\": \"https://api.github.com/users/sjohnr/events{/privacy}\",\n" +
+ " \"received_events_url\": \"https://api.github.com/users/sjohnr/received_events\",\n" +
+ " \"type\": \"User\",\n" +
+ " \"site_admin\": false\n" +
+ " }\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+ this.server.enqueue(new MockResponse().setBody(responseJson));
+ this.github.publishRelease(this.repository, Release.tag("1.0.0").build());
+
+ RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
+ assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("post");
+ assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/releases");
+ assertThat(recordedRequest.getBody().toString()).isEqualTo("{\"tag_name\":\"1.0.0\"}");
+ }
+
+ @Test
+ public void publishReleaseWhenErrorResponseThenException() throws Exception {
+ this.server.enqueue(new MockResponse().setResponseCode(400));
+ assertThatExceptionOfType(RuntimeException.class)
+ .isThrownBy(() -> this.github.publishRelease(this.repository, Release.tag("1.0.0").build()));
+ }
+}
diff --git a/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/build.gradle b/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/build.gradle
index 732278d03b5..48a9859419e 100644
--- a/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/build.gradle
+++ b/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/build.gradle
@@ -9,6 +9,6 @@ repositories {
}
dependencies {
- optional 'javax.servlet:javax.servlet-api:3.1.0'
+ optional 'jakarta.servlet:jakarta.servlet-api:5.0.0'
testCompile 'junit:junit:4.12'
}
\ No newline at end of file
diff --git a/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/src/integration-test/java/sample/TheTest.java b/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/src/integration-test/java/sample/TheTest.java
index de492ca0e67..8bd9ea43927 100644
--- a/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/src/integration-test/java/sample/TheTest.java
+++ b/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/src/integration-test/java/sample/TheTest.java
@@ -1,7 +1,7 @@
package sample;
import org.junit.Test;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
public class TheTest {
@Test
diff --git a/cas/spring-security-cas.gradle b/cas/spring-security-cas.gradle
deleted file mode 100644
index 8b3d4630f75..00000000000
--- a/cas/spring-security-cas.gradle
+++ /dev/null
@@ -1,26 +0,0 @@
-apply plugin: 'io.spring.convention.spring-module'
-
-dependencies {
- management platform(project(":spring-security-dependencies"))
- api project(':spring-security-core')
- api project(':spring-security-web')
- api 'org.jasig.cas.client:cas-client-core'
- api 'org.springframework:spring-beans'
- api 'org.springframework:spring-context'
- api 'org.springframework:spring-core'
- api 'org.springframework:spring-web'
-
- optional 'com.fasterxml.jackson.core:jackson-databind'
- optional 'net.sf.ehcache:ehcache'
-
- provided 'javax.servlet:javax.servlet-api'
-
- testImplementation "org.assertj:assertj-core"
- testImplementation "org.junit.jupiter:junit-jupiter-api"
- testImplementation "org.junit.jupiter:junit-jupiter-params"
- testImplementation "org.junit.jupiter:junit-jupiter-engine"
- testImplementation "org.mockito:mockito-core"
- testImplementation "org.mockito:mockito-junit-jupiter"
- testImplementation "org.springframework:spring-test"
- testImplementation 'org.skyscreamer:jsonassert'
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/SamlServiceProperties.java b/cas/src/main/java/org/springframework/security/cas/SamlServiceProperties.java
deleted file mode 100644
index 8e300f8f8ed..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/SamlServiceProperties.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas;
-
-/**
- * Sets the appropriate parameters for CAS's implementation of SAML (which is not
- * guaranteed to be actually SAML compliant).
- *
- * @author Scott Battaglia
- * @since 3.0
- */
-public final class SamlServiceProperties extends ServiceProperties {
-
- public static final String DEFAULT_SAML_ARTIFACT_PARAMETER = "SAMLart";
-
- public static final String DEFAULT_SAML_SERVICE_PARAMETER = "TARGET";
-
- public SamlServiceProperties() {
- super.setArtifactParameter(DEFAULT_SAML_ARTIFACT_PARAMETER);
- super.setServiceParameter(DEFAULT_SAML_SERVICE_PARAMETER);
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/ServiceProperties.java b/cas/src/main/java/org/springframework/security/cas/ServiceProperties.java
deleted file mode 100644
index caf03dd62a1..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/ServiceProperties.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas;
-
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.util.Assert;
-
-/**
- * Stores properties related to this CAS service.
- *
- * Each web application capable of processing CAS tickets is known as a service. This
- * class stores the properties that are relevant to the local CAS service, being the
- * application that is being secured by Spring Security.
- *
- * @author Ben Alex
- */
-public class ServiceProperties implements InitializingBean {
-
- public static final String DEFAULT_CAS_ARTIFACT_PARAMETER = "ticket";
-
- public static final String DEFAULT_CAS_SERVICE_PARAMETER = "service";
-
- private String service;
-
- private boolean authenticateAllArtifacts;
-
- private boolean sendRenew = false;
-
- private String artifactParameter = DEFAULT_CAS_ARTIFACT_PARAMETER;
-
- private String serviceParameter = DEFAULT_CAS_SERVICE_PARAMETER;
-
- @Override
- public void afterPropertiesSet() {
- Assert.hasLength(this.service, "service cannot be empty.");
- Assert.hasLength(this.artifactParameter, "artifactParameter cannot be empty.");
- Assert.hasLength(this.serviceParameter, "serviceParameter cannot be empty.");
- }
-
- /**
- * Represents the service the user is authenticating to.
- *
- * This service is the callback URL belonging to the local Spring Security System for
- * Spring secured application. For example,
- *
- *
- * @return the URL of the service the user is authenticating to
- */
- public final String getService() {
- return this.service;
- }
-
- /**
- * Indicates whether the renew parameter should be sent to the CAS login
- * URL and CAS validation URL.
- *
- * If true, it will force CAS to authenticate the user again (even if the
- * user has previously authenticated). During ticket validation it will require the
- * ticket was generated as a consequence of an explicit login. High security
- * applications would probably set this to true. Defaults to
- * false, providing automated single sign on.
- * @return whether to send the renew parameter to CAS
- */
- public final boolean isSendRenew() {
- return this.sendRenew;
- }
-
- public final void setSendRenew(final boolean sendRenew) {
- this.sendRenew = sendRenew;
- }
-
- public final void setService(final String service) {
- this.service = service;
- }
-
- public final String getArtifactParameter() {
- return this.artifactParameter;
- }
-
- /**
- * Configures the Request Parameter to look for when attempting to see if a CAS ticket
- * was sent from the server.
- * @param artifactParameter the id to use. Default is "ticket".
- */
- public final void setArtifactParameter(final String artifactParameter) {
- this.artifactParameter = artifactParameter;
- }
-
- /**
- * Configures the Request parameter to look for when attempting to send a request to
- * CAS.
- * @return the service parameter to use. Default is "service".
- */
- public final String getServiceParameter() {
- return this.serviceParameter;
- }
-
- public final void setServiceParameter(final String serviceParameter) {
- this.serviceParameter = serviceParameter;
- }
-
- public final boolean isAuthenticateAllArtifacts() {
- return this.authenticateAllArtifacts;
- }
-
- /**
- * If true, then any non-null artifact (ticket) should be authenticated. Additionally,
- * the service will be determined dynamically in order to ensure the service matches
- * the expected value for this artifact.
- * @param authenticateAllArtifacts
- */
- public final void setAuthenticateAllArtifacts(final boolean authenticateAllArtifacts) {
- this.authenticateAllArtifacts = authenticateAllArtifacts;
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/authentication/CasAssertionAuthenticationToken.java b/cas/src/main/java/org/springframework/security/cas/authentication/CasAssertionAuthenticationToken.java
deleted file mode 100644
index d04d30d1545..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/authentication/CasAssertionAuthenticationToken.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import java.util.ArrayList;
-
-import org.jasig.cas.client.validation.Assertion;
-
-import org.springframework.security.authentication.AbstractAuthenticationToken;
-import org.springframework.security.core.SpringSecurityCoreVersion;
-
-/**
- * Temporary authentication object needed to load the user details service.
- *
- * @author Scott Battaglia
- * @since 3.0
- */
-public final class CasAssertionAuthenticationToken extends AbstractAuthenticationToken {
-
- private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
-
- private final Assertion assertion;
-
- private final String ticket;
-
- public CasAssertionAuthenticationToken(final Assertion assertion, final String ticket) {
- super(new ArrayList<>());
- this.assertion = assertion;
- this.ticket = ticket;
- }
-
- @Override
- public Object getPrincipal() {
- return this.assertion.getPrincipal().getName();
- }
-
- @Override
- public Object getCredentials() {
- return this.ticket;
- }
-
- public Assertion getAssertion() {
- return this.assertion;
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/authentication/CasAuthenticationProvider.java b/cas/src/main/java/org/springframework/security/cas/authentication/CasAuthenticationProvider.java
deleted file mode 100644
index 3a84c2109ae..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/authentication/CasAuthenticationProvider.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jasig.cas.client.validation.Assertion;
-import org.jasig.cas.client.validation.TicketValidationException;
-import org.jasig.cas.client.validation.TicketValidator;
-
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.MessageSource;
-import org.springframework.context.MessageSourceAware;
-import org.springframework.context.support.MessageSourceAccessor;
-import org.springframework.core.log.LogMessage;
-import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
-import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.cas.ServiceProperties;
-import org.springframework.security.cas.web.CasAuthenticationFilter;
-import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.SpringSecurityMessageSource;
-import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
-import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
-import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
-import org.springframework.security.core.userdetails.UserDetailsChecker;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.util.Assert;
-
-/**
- * An {@link AuthenticationProvider} implementation that integrates with JA-SIG Central
- * Authentication Service (CAS).
- *
- * This AuthenticationProvider is capable of validating
- * {@link UsernamePasswordAuthenticationToken} requests which contain a
- * principal name equal to either
- * {@link CasAuthenticationFilter#CAS_STATEFUL_IDENTIFIER} or
- * {@link CasAuthenticationFilter#CAS_STATELESS_IDENTIFIER}. It can also validate a
- * previously created {@link CasAuthenticationToken}.
- *
- * @author Ben Alex
- * @author Scott Battaglia
- */
-public class CasAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
-
- private static final Log logger = LogFactory.getLog(CasAuthenticationProvider.class);
-
- private AuthenticationUserDetailsService authenticationUserDetailsService;
-
- private final UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
-
- protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
-
- private StatelessTicketCache statelessTicketCache = new NullStatelessTicketCache();
-
- private String key;
-
- private TicketValidator ticketValidator;
-
- private ServiceProperties serviceProperties;
-
- private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
-
- @Override
- public void afterPropertiesSet() {
- Assert.notNull(this.authenticationUserDetailsService, "An authenticationUserDetailsService must be set");
- Assert.notNull(this.ticketValidator, "A ticketValidator must be set");
- Assert.notNull(this.statelessTicketCache, "A statelessTicketCache must be set");
- Assert.hasText(this.key,
- "A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated");
- Assert.notNull(this.messages, "A message source must be set");
- }
-
- @Override
- public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- if (!supports(authentication.getClass())) {
- return null;
- }
- if (authentication instanceof UsernamePasswordAuthenticationToken
- && (!CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER.equals(authentication.getPrincipal().toString())
- && !CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER
- .equals(authentication.getPrincipal().toString()))) {
- // UsernamePasswordAuthenticationToken not CAS related
- return null;
- }
- // If an existing CasAuthenticationToken, just check we created it
- if (authentication instanceof CasAuthenticationToken) {
- if (this.key.hashCode() != ((CasAuthenticationToken) authentication).getKeyHash()) {
- throw new BadCredentialsException(this.messages.getMessage("CasAuthenticationProvider.incorrectKey",
- "The presented CasAuthenticationToken does not contain the expected key"));
- }
- return authentication;
- }
-
- // Ensure credentials are presented
- if ((authentication.getCredentials() == null) || "".equals(authentication.getCredentials())) {
- throw new BadCredentialsException(this.messages.getMessage("CasAuthenticationProvider.noServiceTicket",
- "Failed to provide a CAS service ticket to validate"));
- }
-
- boolean stateless = (authentication instanceof UsernamePasswordAuthenticationToken
- && CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER.equals(authentication.getPrincipal()));
- CasAuthenticationToken result = null;
-
- if (stateless) {
- // Try to obtain from cache
- result = this.statelessTicketCache.getByTicketId(authentication.getCredentials().toString());
- }
- if (result == null) {
- result = this.authenticateNow(authentication);
- result.setDetails(authentication.getDetails());
- }
- if (stateless) {
- // Add to cache
- this.statelessTicketCache.putTicketInCache(result);
- }
- return result;
- }
-
- private CasAuthenticationToken authenticateNow(final Authentication authentication) throws AuthenticationException {
- try {
- Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(),
- getServiceUrl(authentication));
- UserDetails userDetails = loadUserByAssertion(assertion);
- this.userDetailsChecker.check(userDetails);
- return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
- this.authoritiesMapper.mapAuthorities(userDetails.getAuthorities()), userDetails, assertion);
- }
- catch (TicketValidationException ex) {
- throw new BadCredentialsException(ex.getMessage(), ex);
- }
- }
-
- /**
- * Gets the serviceUrl. If the {@link Authentication#getDetails()} is an instance of
- * {@link ServiceAuthenticationDetails}, then
- * {@link ServiceAuthenticationDetails#getServiceUrl()} is used. Otherwise, the
- * {@link ServiceProperties#getService()} is used.
- * @param authentication
- * @return
- */
- private String getServiceUrl(Authentication authentication) {
- String serviceUrl;
- if (authentication.getDetails() instanceof ServiceAuthenticationDetails) {
- return ((ServiceAuthenticationDetails) authentication.getDetails()).getServiceUrl();
- }
- Assert.state(this.serviceProperties != null,
- "serviceProperties cannot be null unless Authentication.getDetails() implements ServiceAuthenticationDetails.");
- Assert.state(this.serviceProperties.getService() != null,
- "serviceProperties.getService() cannot be null unless Authentication.getDetails() implements ServiceAuthenticationDetails.");
- serviceUrl = this.serviceProperties.getService();
- logger.debug(LogMessage.format("serviceUrl = %s", serviceUrl));
- return serviceUrl;
- }
-
- /**
- * Template method for retrieving the UserDetails based on the assertion. Default is
- * to call configured userDetailsService and pass the username. Deployers can override
- * this method and retrieve the user based on any criteria they desire.
- * @param assertion The CAS Assertion.
- * @return the UserDetails.
- */
- protected UserDetails loadUserByAssertion(final Assertion assertion) {
- final CasAssertionAuthenticationToken token = new CasAssertionAuthenticationToken(assertion, "");
- return this.authenticationUserDetailsService.loadUserDetails(token);
- }
-
- @SuppressWarnings("unchecked")
- /**
- * Sets the UserDetailsService to use. This is a convenience method to invoke
- */
- public void setUserDetailsService(final UserDetailsService userDetailsService) {
- this.authenticationUserDetailsService = new UserDetailsByNameServiceWrapper(userDetailsService);
- }
-
- public void setAuthenticationUserDetailsService(
- final AuthenticationUserDetailsService authenticationUserDetailsService) {
- this.authenticationUserDetailsService = authenticationUserDetailsService;
- }
-
- public void setServiceProperties(final ServiceProperties serviceProperties) {
- this.serviceProperties = serviceProperties;
- }
-
- protected String getKey() {
- return this.key;
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public StatelessTicketCache getStatelessTicketCache() {
- return this.statelessTicketCache;
- }
-
- protected TicketValidator getTicketValidator() {
- return this.ticketValidator;
- }
-
- @Override
- public void setMessageSource(final MessageSource messageSource) {
- this.messages = new MessageSourceAccessor(messageSource);
- }
-
- public void setStatelessTicketCache(final StatelessTicketCache statelessTicketCache) {
- this.statelessTicketCache = statelessTicketCache;
- }
-
- public void setTicketValidator(final TicketValidator ticketValidator) {
- this.ticketValidator = ticketValidator;
- }
-
- public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
- this.authoritiesMapper = authoritiesMapper;
- }
-
- @Override
- public boolean supports(final Class> authentication) {
- return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication))
- || (CasAuthenticationToken.class.isAssignableFrom(authentication))
- || (CasAssertionAuthenticationToken.class.isAssignableFrom(authentication));
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/authentication/CasAuthenticationToken.java b/cas/src/main/java/org/springframework/security/cas/authentication/CasAuthenticationToken.java
deleted file mode 100644
index 8020da0400a..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/authentication/CasAuthenticationToken.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import java.io.Serializable;
-import java.util.Collection;
-
-import org.jasig.cas.client.validation.Assertion;
-
-import org.springframework.security.authentication.AbstractAuthenticationToken;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.SpringSecurityCoreVersion;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.util.Assert;
-import org.springframework.util.ObjectUtils;
-
-/**
- * Represents a successful CAS Authentication.
- *
- * @author Ben Alex
- * @author Scott Battaglia
- */
-public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
-
- private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
-
- private final Object credentials;
-
- private final Object principal;
-
- private final UserDetails userDetails;
-
- private final int keyHash;
-
- private final Assertion assertion;
-
- /**
- * Constructor.
- * @param key to identify if this object made by a given
- * {@link CasAuthenticationProvider}
- * @param principal typically the UserDetails object (cannot be null)
- * @param credentials the service/proxy ticket ID from CAS (cannot be
- * null)
- * @param authorities the authorities granted to the user (from the
- * {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
- * be null)
- * @param userDetails the user details (from the
- * {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
- * be null)
- * @param assertion the assertion returned from the CAS servers. It contains the
- * principal and how to obtain a proxy ticket for the user.
- * @throws IllegalArgumentException if a null was passed
- */
- public CasAuthenticationToken(final String key, final Object principal, final Object credentials,
- final Collection extends GrantedAuthority> authorities, final UserDetails userDetails,
- final Assertion assertion) {
- this(extractKeyHash(key), principal, credentials, authorities, userDetails, assertion);
- }
-
- /**
- * Private constructor for Jackson Deserialization support
- * @param keyHash hashCode of provided key to identify if this object made by a given
- * {@link CasAuthenticationProvider}
- * @param principal typically the UserDetails object (cannot be null)
- * @param credentials the service/proxy ticket ID from CAS (cannot be
- * null)
- * @param authorities the authorities granted to the user (from the
- * {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
- * be null)
- * @param userDetails the user details (from the
- * {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
- * be null)
- * @param assertion the assertion returned from the CAS servers. It contains the
- * principal and how to obtain a proxy ticket for the user.
- * @throws IllegalArgumentException if a null was passed
- * @since 4.2
- */
- private CasAuthenticationToken(final Integer keyHash, final Object principal, final Object credentials,
- final Collection extends GrantedAuthority> authorities, final UserDetails userDetails,
- final Assertion assertion) {
- super(authorities);
- if ((principal == null) || "".equals(principal) || (credentials == null) || "".equals(credentials)
- || (authorities == null) || (userDetails == null) || (assertion == null)) {
- throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
- }
- this.keyHash = keyHash;
- this.principal = principal;
- this.credentials = credentials;
- this.userDetails = userDetails;
- this.assertion = assertion;
- setAuthenticated(true);
- }
-
- private static Integer extractKeyHash(String key) {
- Assert.hasLength(key, "key cannot be null or empty");
- return key.hashCode();
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (!super.equals(obj)) {
- return false;
- }
- if (obj instanceof CasAuthenticationToken) {
- CasAuthenticationToken test = (CasAuthenticationToken) obj;
- if (!this.assertion.equals(test.getAssertion())) {
- return false;
- }
- if (this.getKeyHash() != test.getKeyHash()) {
- return false;
- }
- return true;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int result = super.hashCode();
- result = 31 * result + this.credentials.hashCode();
- result = 31 * result + this.principal.hashCode();
- result = 31 * result + this.userDetails.hashCode();
- result = 31 * result + this.keyHash;
- result = 31 * result + ObjectUtils.nullSafeHashCode(this.assertion);
- return result;
- }
-
- @Override
- public Object getCredentials() {
- return this.credentials;
- }
-
- public int getKeyHash() {
- return this.keyHash;
- }
-
- @Override
- public Object getPrincipal() {
- return this.principal;
- }
-
- public Assertion getAssertion() {
- return this.assertion;
- }
-
- public UserDetails getUserDetails() {
- return this.userDetails;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(super.toString());
- sb.append(" Assertion: ").append(this.assertion);
- sb.append(" Credentials (Service/Proxy Ticket): ").append(this.credentials);
- return (sb.toString());
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/authentication/EhCacheBasedTicketCache.java b/cas/src/main/java/org/springframework/security/cas/authentication/EhCacheBasedTicketCache.java
deleted file mode 100644
index 595c0d23f2e..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/authentication/EhCacheBasedTicketCache.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import net.sf.ehcache.Ehcache;
-import net.sf.ehcache.Element;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.core.log.LogMessage;
-import org.springframework.util.Assert;
-
-/**
- * Caches tickets using a Spring IoC defined
- * EHCACHE.
- *
- * @author Ben Alex
- * @deprecated since 5.6. In favor of JCache based implementations
- */
-@Deprecated
-public class EhCacheBasedTicketCache implements StatelessTicketCache, InitializingBean {
-
- private static final Log logger = LogFactory.getLog(EhCacheBasedTicketCache.class);
-
- private Ehcache cache;
-
- @Override
- public void afterPropertiesSet() {
- Assert.notNull(this.cache, "cache mandatory");
- }
-
- @Override
- public CasAuthenticationToken getByTicketId(final String serviceTicket) {
- final Element element = this.cache.get(serviceTicket);
- logger.debug(LogMessage.of(() -> "Cache hit: " + (element != null) + "; service ticket: " + serviceTicket));
- return (element != null) ? (CasAuthenticationToken) element.getValue() : null;
- }
-
- public Ehcache getCache() {
- return this.cache;
- }
-
- @Override
- public void putTicketInCache(final CasAuthenticationToken token) {
- final Element element = new Element(token.getCredentials().toString(), token);
- logger.debug(LogMessage.of(() -> "Cache put: " + element.getKey()));
- this.cache.put(element);
- }
-
- @Override
- public void removeTicketFromCache(final CasAuthenticationToken token) {
- logger.debug(LogMessage.of(() -> "Cache remove: " + token.getCredentials().toString()));
- this.removeTicketFromCache(token.getCredentials().toString());
- }
-
- @Override
- public void removeTicketFromCache(final String serviceTicket) {
- this.cache.remove(serviceTicket);
- }
-
- public void setCache(final Ehcache cache) {
- this.cache = cache;
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/authentication/NullStatelessTicketCache.java b/cas/src/main/java/org/springframework/security/cas/authentication/NullStatelessTicketCache.java
deleted file mode 100644
index 4284161a39a..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/authentication/NullStatelessTicketCache.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-/**
- * Implementation of @link {@link StatelessTicketCache} that has no backing cache. Useful
- * in instances where storing of tickets for stateless session management is not required.
- *
- * This is the default StatelessTicketCache of the @link {@link CasAuthenticationProvider}
- * to eliminate the unnecessary dependency on EhCache that applications have even if they
- * are not using the stateless session management.
- *
- * @author Scott Battaglia
- * @see CasAuthenticationProvider
- */
-public final class NullStatelessTicketCache implements StatelessTicketCache {
-
- /**
- * @return null since we are not storing any tickets.
- */
- @Override
- public CasAuthenticationToken getByTicketId(final String serviceTicket) {
- return null;
- }
-
- /**
- * This is a no-op since we are not storing tickets.
- */
- @Override
- public void putTicketInCache(final CasAuthenticationToken token) {
- // nothing to do
- }
-
- /**
- * This is a no-op since we are not storing tickets.
- */
- @Override
- public void removeTicketFromCache(final CasAuthenticationToken token) {
- // nothing to do
- }
-
- /**
- * This is a no-op since we are not storing tickets.
- */
- @Override
- public void removeTicketFromCache(final String serviceTicket) {
- // nothing to do
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/authentication/SpringCacheBasedTicketCache.java b/cas/src/main/java/org/springframework/security/cas/authentication/SpringCacheBasedTicketCache.java
deleted file mode 100644
index b72e824c75f..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/authentication/SpringCacheBasedTicketCache.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.cache.Cache;
-import org.springframework.core.log.LogMessage;
-import org.springframework.util.Assert;
-
-/**
- * Caches tickets using a Spring IoC defined {@link Cache}.
- *
- * @author Marten Deinum
- * @since 3.2
- *
- */
-public class SpringCacheBasedTicketCache implements StatelessTicketCache {
-
- private static final Log logger = LogFactory.getLog(SpringCacheBasedTicketCache.class);
-
- private final Cache cache;
-
- public SpringCacheBasedTicketCache(Cache cache) {
- Assert.notNull(cache, "cache mandatory");
- this.cache = cache;
- }
-
- @Override
- public CasAuthenticationToken getByTicketId(final String serviceTicket) {
- final Cache.ValueWrapper element = (serviceTicket != null) ? this.cache.get(serviceTicket) : null;
- logger.debug(LogMessage.of(() -> "Cache hit: " + (element != null) + "; service ticket: " + serviceTicket));
- return (element != null) ? (CasAuthenticationToken) element.get() : null;
- }
-
- @Override
- public void putTicketInCache(final CasAuthenticationToken token) {
- String key = token.getCredentials().toString();
- logger.debug(LogMessage.of(() -> "Cache put: " + key));
- this.cache.put(key, token);
- }
-
- @Override
- public void removeTicketFromCache(final CasAuthenticationToken token) {
- logger.debug(LogMessage.of(() -> "Cache remove: " + token.getCredentials().toString()));
- this.removeTicketFromCache(token.getCredentials().toString());
- }
-
- @Override
- public void removeTicketFromCache(final String serviceTicket) {
- this.cache.evict(serviceTicket);
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/authentication/StatelessTicketCache.java b/cas/src/main/java/org/springframework/security/cas/authentication/StatelessTicketCache.java
deleted file mode 100644
index 74df6bb9df4..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/authentication/StatelessTicketCache.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2004 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-/**
- * Caches CAS service tickets and CAS proxy tickets for stateless connections.
- *
- *
- * When a service ticket or proxy ticket is validated against the CAS server, it is unable
- * to be used again. Most types of callers are stateful and are associated with a given
- * HttpSession. This allows the affirmative CAS validation outcome to be
- * stored in the HttpSession, meaning the removal of the ticket from the CAS
- * server is not an issue.
- *
- *
- *
- * Stateless callers, such as remoting protocols, cannot take advantage of
- * HttpSession. If the stateless caller is located a significant network
- * distance from the CAS server, acquiring a fresh service ticket or proxy ticket for each
- * invocation would be expensive.
- *
- *
- *
- * To avoid this issue with stateless callers, it is expected stateless callers will
- * obtain a single service ticket or proxy ticket, and then present this same ticket to
- * the Spring Security secured application on each occasion. As no
- * HttpSession is available for such callers, the affirmative CAS validation
- * outcome cannot be stored in this location.
- *
- *
- *
- * The StatelessTicketCache enables the service tickets and proxy tickets
- * belonging to stateless callers to be placed in a cache. This in-memory cache stores the
- * CasAuthenticationToken, effectively providing the same capability as a
- * HttpSession with the ticket identifier being the key rather than a session
- * identifier.
- *
- *
- *
- * Implementations should provide a reasonable timeout on stored entries, such that the
- * stateless caller are not required to unnecessarily acquire fresh CAS service tickets or
- * proxy tickets.
- *
- *
- * @author Ben Alex
- */
-public interface StatelessTicketCache {
-
- /**
- * Retrieves the CasAuthenticationToken associated with the specified
- * ticket.
- *
- *
- * If not found, returns a nullCasAuthenticationToken.
- *
- * @return the fully populated authentication token
- */
- CasAuthenticationToken getByTicketId(String serviceTicket);
-
- /**
- * Adds the specified CasAuthenticationToken to the cache.
- *
- *
- * The {@link CasAuthenticationToken#getCredentials()} method is used to retrieve the
- * service ticket number.
- *
- * @param token to be added to the cache
- */
- void putTicketInCache(CasAuthenticationToken token);
-
- /**
- * Removes the specified ticket from the cache, as per
- * {@link #removeTicketFromCache(String)}.
- *
- *
- * Implementations should use {@link CasAuthenticationToken#getCredentials()} to
- * obtain the ticket and then delegate to the {@link #removeTicketFromCache(String)}
- * method.
- *
- * @param token to be removed
- */
- void removeTicketFromCache(CasAuthenticationToken token);
-
- /**
- * Removes the specified ticket from the cache, meaning that future calls will require
- * a new service ticket.
- *
- *
- * This is in case applications wish to provide a session termination capability for
- * their stateless clients.
- *
- * @param serviceTicket to be removed
- */
- void removeTicketFromCache(String serviceTicket);
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/authentication/package-info.java b/cas/src/main/java/org/springframework/security/cas/authentication/package-info.java
deleted file mode 100644
index 8803500a0a2..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/authentication/package-info.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2002-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * An {@code AuthenticationProvider} that can process CAS service tickets and proxy
- * tickets.
- */
-package org.springframework.security.cas.authentication;
diff --git a/cas/src/main/java/org/springframework/security/cas/jackson2/AssertionImplMixin.java b/cas/src/main/java/org/springframework/security/cas/jackson2/AssertionImplMixin.java
deleted file mode 100644
index f3d7de8c025..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/jackson2/AssertionImplMixin.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2015-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.jackson2;
-
-import java.util.Date;
-import java.util.Map;
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.jasig.cas.client.authentication.AttributePrincipal;
-
-/**
- * Helps in jackson deserialization of class
- * {@link org.jasig.cas.client.validation.AssertionImpl}, which is used with
- * {@link org.springframework.security.cas.authentication.CasAuthenticationToken}. To use
- * this class we need to register with
- * {@link com.fasterxml.jackson.databind.ObjectMapper}. Type information will be stored
- * in @class property.
- *
- *
- * @author Jitendra Singh
- * @since 4.2
- * @see CasJackson2Module
- * @see org.springframework.security.jackson2.SecurityJackson2Modules
- */
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
-@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
- isGetterVisibility = JsonAutoDetect.Visibility.NONE)
-@JsonIgnoreProperties(ignoreUnknown = true)
-class AssertionImplMixin {
-
- /**
- * Mixin Constructor helps in deserialize
- * {@link org.jasig.cas.client.validation.AssertionImpl}
- * @param principal the Principal to associate with the Assertion.
- * @param validFromDate when the assertion is valid from.
- * @param validUntilDate when the assertion is valid to.
- * @param authenticationDate when the assertion is authenticated.
- * @param attributes the key/value pairs for this attribute.
- */
- @JsonCreator
- AssertionImplMixin(@JsonProperty("principal") AttributePrincipal principal,
- @JsonProperty("validFromDate") Date validFromDate, @JsonProperty("validUntilDate") Date validUntilDate,
- @JsonProperty("authenticationDate") Date authenticationDate,
- @JsonProperty("attributes") Map attributes) {
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/jackson2/AttributePrincipalImplMixin.java b/cas/src/main/java/org/springframework/security/cas/jackson2/AttributePrincipalImplMixin.java
deleted file mode 100644
index 0ec671fb557..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/jackson2/AttributePrincipalImplMixin.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2015-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.jackson2;
-
-import java.util.Map;
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.jasig.cas.client.proxy.ProxyRetriever;
-
-/**
- * Helps in deserialize {@link org.jasig.cas.client.authentication.AttributePrincipalImpl}
- * which is used with
- * {@link org.springframework.security.cas.authentication.CasAuthenticationToken}. Type
- * information will be stored in property named @class.
- *
- *
- * @author Jitendra Singh
- * @since 4.2
- * @see CasJackson2Module
- * @see org.springframework.security.jackson2.SecurityJackson2Modules
- */
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
-@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
- isGetterVisibility = JsonAutoDetect.Visibility.NONE)
-@JsonIgnoreProperties(ignoreUnknown = true)
-class AttributePrincipalImplMixin {
-
- /**
- * Mixin Constructor helps in deserialize
- * {@link org.jasig.cas.client.authentication.AttributePrincipalImpl}
- * @param name the unique identifier for the principal.
- * @param attributes the key/value pairs for this principal.
- * @param proxyGrantingTicket the ticket associated with this principal.
- * @param proxyRetriever the ProxyRetriever implementation to call back to the CAS
- * server.
- */
- @JsonCreator
- AttributePrincipalImplMixin(@JsonProperty("name") String name,
- @JsonProperty("attributes") Map attributes,
- @JsonProperty("proxyGrantingTicket") String proxyGrantingTicket,
- @JsonProperty("proxyRetriever") ProxyRetriever proxyRetriever) {
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/jackson2/CasAuthenticationTokenMixin.java b/cas/src/main/java/org/springframework/security/cas/jackson2/CasAuthenticationTokenMixin.java
deleted file mode 100644
index 80e40a0dcaf..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/jackson2/CasAuthenticationTokenMixin.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2015-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.jackson2;
-
-import java.util.Collection;
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.jasig.cas.client.validation.Assertion;
-
-import org.springframework.security.cas.authentication.CasAuthenticationProvider;
-import org.springframework.security.cas.authentication.CasAuthenticationToken;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-
-/**
- * Mixin class which helps in deserialize
- * {@link org.springframework.security.cas.authentication.CasAuthenticationToken} using
- * jackson. Two more dependent classes needs to register along with this mixin class.
- *
- *
- *
- * @author Jitendra Singh
- * @since 4.2
- * @see CasJackson2Module
- * @see org.springframework.security.jackson2.SecurityJackson2Modules
- */
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
-@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE,
- getterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.ANY)
-@JsonIgnoreProperties(ignoreUnknown = true)
-class CasAuthenticationTokenMixin {
-
- /**
- * Mixin Constructor helps in deserialize {@link CasAuthenticationToken}
- * @param keyHash hashCode of provided key to identify if this object made by a given
- * {@link CasAuthenticationProvider}
- * @param principal typically the UserDetails object (cannot be null)
- * @param credentials the service/proxy ticket ID from CAS (cannot be
- * null)
- * @param authorities the authorities granted to the user (from the
- * {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
- * be null)
- * @param userDetails the user details (from the
- * {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
- * be null)
- * @param assertion the assertion returned from the CAS servers. It contains the
- * principal and how to obtain a proxy ticket for the user.
- */
- @JsonCreator
- CasAuthenticationTokenMixin(@JsonProperty("keyHash") Integer keyHash, @JsonProperty("principal") Object principal,
- @JsonProperty("credentials") Object credentials,
- @JsonProperty("authorities") Collection extends GrantedAuthority> authorities,
- @JsonProperty("userDetails") UserDetails userDetails, @JsonProperty("assertion") Assertion assertion) {
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/jackson2/CasJackson2Module.java b/cas/src/main/java/org/springframework/security/cas/jackson2/CasJackson2Module.java
deleted file mode 100644
index 34f19ca10af..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/jackson2/CasJackson2Module.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2015-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.jackson2;
-
-import com.fasterxml.jackson.core.Version;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import org.jasig.cas.client.authentication.AttributePrincipalImpl;
-import org.jasig.cas.client.validation.AssertionImpl;
-
-import org.springframework.security.cas.authentication.CasAuthenticationToken;
-import org.springframework.security.jackson2.SecurityJackson2Modules;
-
-/**
- * Jackson module for spring-security-cas. This module register
- * {@link AssertionImplMixin}, {@link AttributePrincipalImplMixin} and
- * {@link CasAuthenticationTokenMixin}. If no default typing enabled by default then it'll
- * enable it because typing info is needed to properly serialize/deserialize objects. In
- * order to use this module just add this module into your ObjectMapper configuration.
- *
- *
Note: use {@link SecurityJackson2Modules#getModules(ClassLoader)} to get list
- * of all security modules on the classpath.
- *
- * @author Jitendra Singh.
- * @since 4.2
- * @see org.springframework.security.jackson2.SecurityJackson2Modules
- */
-public class CasJackson2Module extends SimpleModule {
-
- public CasJackson2Module() {
- super(CasJackson2Module.class.getName(), new Version(1, 0, 0, null, null, null));
- }
-
- @Override
- public void setupModule(SetupContext context) {
- SecurityJackson2Modules.enableDefaultTyping(context.getOwner());
- context.setMixInAnnotations(AssertionImpl.class, AssertionImplMixin.class);
- context.setMixInAnnotations(AttributePrincipalImpl.class, AttributePrincipalImplMixin.class);
- context.setMixInAnnotations(CasAuthenticationToken.class, CasAuthenticationTokenMixin.class);
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/package-info.java b/cas/src/main/java/org/springframework/security/cas/package-info.java
deleted file mode 100644
index 13fae9057d0..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/package-info.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2002-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Spring Security support for Jasig's Central Authentication Service
- * (CAS).
- */
-package org.springframework.security.cas;
diff --git a/cas/src/main/java/org/springframework/security/cas/userdetails/AbstractCasAssertionUserDetailsService.java b/cas/src/main/java/org/springframework/security/cas/userdetails/AbstractCasAssertionUserDetailsService.java
deleted file mode 100644
index 3d8cd9e412a..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/userdetails/AbstractCasAssertionUserDetailsService.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.userdetails;
-
-import org.jasig.cas.client.validation.Assertion;
-
-import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
-import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
-import org.springframework.security.core.userdetails.UserDetails;
-
-/**
- * Abstract class for using the provided CAS assertion to construct a new User object.
- * This generally is most useful when combined with a SAML-based response from the CAS
- * Server/client.
- *
- * @author Scott Battaglia
- * @since 3.0
- */
-public abstract class AbstractCasAssertionUserDetailsService
- implements AuthenticationUserDetailsService {
-
- @Override
- public final UserDetails loadUserDetails(final CasAssertionAuthenticationToken token) {
- return loadUserDetails(token.getAssertion());
- }
-
- /**
- * Protected template method for construct a
- * {@link org.springframework.security.core.userdetails.UserDetails} via the supplied
- * CAS assertion.
- * @param assertion the assertion to use to construct the new UserDetails. CANNOT be
- * NULL.
- * @return the newly constructed UserDetails.
- */
- protected abstract UserDetails loadUserDetails(Assertion assertion);
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/userdetails/GrantedAuthorityFromAssertionAttributesUserDetailsService.java b/cas/src/main/java/org/springframework/security/cas/userdetails/GrantedAuthorityFromAssertionAttributesUserDetailsService.java
deleted file mode 100644
index 0e47d1c57f8..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/userdetails/GrantedAuthorityFromAssertionAttributesUserDetailsService.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.userdetails;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.jasig.cas.client.validation.Assertion;
-
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.util.Assert;
-
-/**
- * Populates the {@link org.springframework.security.core.GrantedAuthority}s for a user by
- * reading a list of attributes that were returned as part of the CAS response. Each
- * attribute is read and each value of the attribute is turned into a GrantedAuthority. If
- * the attribute has no value then its not added.
- *
- * @author Scott Battaglia
- * @since 3.0
- */
-public final class GrantedAuthorityFromAssertionAttributesUserDetailsService
- extends AbstractCasAssertionUserDetailsService {
-
- private static final String NON_EXISTENT_PASSWORD_VALUE = "NO_PASSWORD";
-
- private final String[] attributes;
-
- private boolean convertToUpperCase = true;
-
- public GrantedAuthorityFromAssertionAttributesUserDetailsService(final String[] attributes) {
- Assert.notNull(attributes, "attributes cannot be null.");
- Assert.isTrue(attributes.length > 0, "At least one attribute is required to retrieve roles from.");
- this.attributes = attributes;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected UserDetails loadUserDetails(final Assertion assertion) {
- List grantedAuthorities = new ArrayList<>();
- for (String attribute : this.attributes) {
- Object value = assertion.getPrincipal().getAttributes().get(attribute);
- if (value != null) {
- if (value instanceof List) {
- for (Object o : (List>) value) {
- grantedAuthorities.add(createSimpleGrantedAuthority(o));
- }
- }
- else {
- grantedAuthorities.add(createSimpleGrantedAuthority(value));
- }
- }
- }
- return new User(assertion.getPrincipal().getName(), NON_EXISTENT_PASSWORD_VALUE, true, true, true, true,
- grantedAuthorities);
- }
-
- private SimpleGrantedAuthority createSimpleGrantedAuthority(Object o) {
- return new SimpleGrantedAuthority(this.convertToUpperCase ? o.toString().toUpperCase() : o.toString());
- }
-
- /**
- * Converts the returned attribute values to uppercase values.
- * @param convertToUpperCase true if it should convert, false otherwise.
- */
- public void setConvertToUpperCase(final boolean convertToUpperCase) {
- this.convertToUpperCase = convertToUpperCase;
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationEntryPoint.java b/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationEntryPoint.java
deleted file mode 100644
index 25221addf8c..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationEntryPoint.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.web;
-
-import java.io.IOException;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.jasig.cas.client.util.CommonUtils;
-
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.security.cas.ServiceProperties;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.util.Assert;
-
-/**
- * Used by the ExceptionTranslationFilter to commence authentication via the
- * JA-SIG Central Authentication Service (CAS).
- *
- * The user's browser will be redirected to the JA-SIG CAS enterprise-wide login page.
- * This page is specified by the loginUrl property. Once login is complete,
- * the CAS login page will redirect to the page indicated by the service
- * property. The service is a HTTP URL belonging to the current application.
- * The service URL is monitored by the {@link CasAuthenticationFilter}, which
- * will validate the CAS login was successful.
- *
- * @author Ben Alex
- * @author Scott Battaglia
- */
-public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, InitializingBean {
-
- private ServiceProperties serviceProperties;
-
- private String loginUrl;
-
- /**
- * Determines whether the Service URL should include the session id for the specific
- * user. As of CAS 3.0.5, the session id will automatically be stripped. However,
- * older versions of CAS (i.e. CAS 2), do not automatically strip the session
- * identifier (this is a bug on the part of the older server implementations), so an
- * option to disable the session encoding is provided for backwards compatibility.
- *
- * By default, encoding is enabled.
- */
- private boolean encodeServiceUrlWithSessionId = true;
-
- @Override
- public void afterPropertiesSet() {
- Assert.hasLength(this.loginUrl, "loginUrl must be specified");
- Assert.notNull(this.serviceProperties, "serviceProperties must be specified");
- Assert.notNull(this.serviceProperties.getService(), "serviceProperties.getService() cannot be null.");
- }
-
- @Override
- public final void commence(final HttpServletRequest servletRequest, HttpServletResponse response,
- AuthenticationException authenticationException) throws IOException {
- String urlEncodedService = createServiceUrl(servletRequest, response);
- String redirectUrl = createRedirectUrl(urlEncodedService);
- preCommence(servletRequest, response);
- response.sendRedirect(redirectUrl);
- }
-
- /**
- * Constructs a new Service Url. The default implementation relies on the CAS client
- * to do the bulk of the work.
- * @param request the HttpServletRequest
- * @param response the HttpServlet Response
- * @return the constructed service url. CANNOT be NULL.
- */
- protected String createServiceUrl(HttpServletRequest request, HttpServletResponse response) {
- return CommonUtils.constructServiceUrl(null, response, this.serviceProperties.getService(), null,
- this.serviceProperties.getArtifactParameter(), this.encodeServiceUrlWithSessionId);
- }
-
- /**
- * Constructs the Url for Redirection to the CAS server. Default implementation relies
- * on the CAS client to do the bulk of the work.
- * @param serviceUrl the service url that should be included.
- * @return the redirect url. CANNOT be NULL.
- */
- protected String createRedirectUrl(String serviceUrl) {
- return CommonUtils.constructRedirectUrl(this.loginUrl, this.serviceProperties.getServiceParameter(), serviceUrl,
- this.serviceProperties.isSendRenew(), false);
- }
-
- /**
- * Template method for you to do your own pre-processing before the redirect occurs.
- * @param request the HttpServletRequest
- * @param response the HttpServletResponse
- */
- protected void preCommence(HttpServletRequest request, HttpServletResponse response) {
-
- }
-
- /**
- * The enterprise-wide CAS login URL. Usually something like
- * https://www.mycompany.com/cas/login.
- * @return the enterprise-wide CAS login URL
- */
- public final String getLoginUrl() {
- return this.loginUrl;
- }
-
- public final ServiceProperties getServiceProperties() {
- return this.serviceProperties;
- }
-
- public final void setLoginUrl(String loginUrl) {
- this.loginUrl = loginUrl;
- }
-
- public final void setServiceProperties(ServiceProperties serviceProperties) {
- this.serviceProperties = serviceProperties;
- }
-
- /**
- * Sets whether to encode the service url with the session id or not.
- * @param encodeServiceUrlWithSessionId whether to encode the service url with the
- * session id or not.
- */
- public final void setEncodeServiceUrlWithSessionId(boolean encodeServiceUrlWithSessionId) {
- this.encodeServiceUrlWithSessionId = encodeServiceUrlWithSessionId;
- }
-
- /**
- * Sets whether to encode the service url with the session id or not.
- * @return whether to encode the service url with the session id or not.
- *
- */
- protected boolean getEncodeServiceUrlWithSessionId() {
- return this.encodeServiceUrlWithSessionId;
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java b/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java
deleted file mode 100644
index 2352887b1f7..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.web;
-
-import java.io.IOException;
-
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
-import org.jasig.cas.client.util.CommonUtils;
-import org.jasig.cas.client.validation.TicketValidator;
-
-import org.springframework.core.log.LogMessage;
-import org.springframework.security.authentication.AnonymousAuthenticationToken;
-import org.springframework.security.authentication.AuthenticationDetailsSource;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
-import org.springframework.security.cas.ServiceProperties;
-import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
-import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
-import org.springframework.security.web.authentication.AuthenticationFailureHandler;
-import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.security.web.util.matcher.RequestMatcher;
-import org.springframework.util.Assert;
-
-/**
- * Processes a CAS service ticket, obtains proxy granting tickets, and processes proxy
- * tickets.
- *
Service Tickets
- *
- * A service ticket consists of an opaque ticket string. It arrives at this filter by the
- * user's browser successfully authenticating using CAS, and then receiving a HTTP
- * redirect to a service. The opaque ticket string is presented in the
- * ticket request parameter.
- *
- * This filter monitors the service URL so it can receive the service ticket
- * and process it. By default this filter processes the URL /login/cas. When
- * processing this URL, the value of {@link ServiceProperties#getService()} is used as the
- * service when validating the ticket. This means that it is
- * important that {@link ServiceProperties#getService()} specifies the same value as the
- * filterProcessesUrl.
- *
- * Processing the service ticket involves creating a
- * UsernamePasswordAuthenticationToken which uses
- * {@link #CAS_STATEFUL_IDENTIFIER} for the principal and the opaque ticket
- * string as the credentials.
- *
Obtaining Proxy Granting Tickets
- *
- * If specified, the filter can also monitor the proxyReceptorUrl. The filter
- * will respond to requests matching this url so that the CAS Server can provide a PGT to
- * the filter. Note that in addition to the proxyReceptorUrl a non-null
- * proxyGrantingTicketStorage must be provided in order for the filter to
- * respond to proxy receptor requests. By configuring a shared
- * {@link ProxyGrantingTicketStorage} between the {@link TicketValidator} and the
- * CasAuthenticationFilter one can have the CasAuthenticationFilter handle the proxying
- * requirements for CAS.
- *
Proxy Tickets
- *
- * The filter can process tickets present on any url. This is useful when wanting to
- * process proxy tickets. In order for proxy tickets to get processed
- * {@link ServiceProperties#isAuthenticateAllArtifacts()} must return true.
- * Additionally, if the request is already authenticated, authentication will not
- * occur. Last, {@link AuthenticationDetailsSource#buildDetails(Object)} must return a
- * {@link ServiceAuthenticationDetails}. This can be accomplished using the
- * {@link ServiceAuthenticationDetailsSource}. In this case
- * {@link ServiceAuthenticationDetails#getServiceUrl()} will be used for the service url.
- *
- * Processing the proxy ticket involves creating a
- * UsernamePasswordAuthenticationToken which uses
- * {@link #CAS_STATELESS_IDENTIFIER} for the principal and the opaque ticket
- * string as the credentials. When a proxy ticket is successfully
- * authenticated, the FilterChain continues and the
- * authenticationSuccessHandler is not used.
- *
Notes about the AuthenticationManager
- *
- * The configured AuthenticationManager is expected to provide a provider
- * that can recognise UsernamePasswordAuthenticationTokens containing this
- * special principal name, and process them accordingly by validation with
- * the CAS server. Additionally, it should be capable of using the result of
- * {@link ServiceAuthenticationDetails#getServiceUrl()} as the service when validating the
- * ticket.
- *
Example Configuration
- *
- * An example configuration that supports service tickets, obtaining proxy granting
- * tickets, and proxy tickets is illustrated below:
- *
- *
- *
- * @author Ben Alex
- * @author Rob Winch
- */
-public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
-
- /**
- * Used to identify a CAS request for a stateful user agent, such as a web browser.
- */
- public static final String CAS_STATEFUL_IDENTIFIER = "_cas_stateful_";
-
- /**
- * Used to identify a CAS request for a stateless user agent, such as a remoting
- * protocol client (e.g. Hessian, Burlap, SOAP etc). Results in a more aggressive
- * caching strategy being used, as the absence of a HttpSession will
- * result in a new authentication attempt on every request.
- */
- public static final String CAS_STATELESS_IDENTIFIER = "_cas_stateless_";
-
- /**
- * The last portion of the receptor url, i.e. /proxy/receptor
- */
- private RequestMatcher proxyReceptorMatcher;
-
- /**
- * The backing storage to store ProxyGrantingTicket requests.
- */
- private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
-
- private String artifactParameter = ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER;
-
- private boolean authenticateAllArtifacts;
-
- private AuthenticationFailureHandler proxyFailureHandler = new SimpleUrlAuthenticationFailureHandler();
-
- public CasAuthenticationFilter() {
- super("/login/cas");
- setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
- }
-
- @Override
- protected final void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
- FilterChain chain, Authentication authResult) throws IOException, ServletException {
- boolean continueFilterChain = proxyTicketRequest(serviceTicketRequest(request, response), request);
- if (!continueFilterChain) {
- super.successfulAuthentication(request, response, chain, authResult);
- return;
- }
- this.logger.debug(
- LogMessage.format("Authentication success. Updating SecurityContextHolder to contain: %s", authResult));
- SecurityContext context = SecurityContextHolder.createEmptyContext();
- context.setAuthentication(authResult);
- SecurityContextHolder.setContext(context);
- if (this.eventPublisher != null) {
- this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
- }
- chain.doFilter(request, response);
- }
-
- @Override
- public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
- throws AuthenticationException, IOException {
- // if the request is a proxy request process it and return null to indicate the
- // request has been processed
- if (proxyReceptorRequest(request)) {
- this.logger.debug("Responding to proxy receptor request");
- CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
- return null;
- }
- boolean serviceTicketRequest = serviceTicketRequest(request, response);
- String username = serviceTicketRequest ? CAS_STATEFUL_IDENTIFIER : CAS_STATELESS_IDENTIFIER;
- String password = obtainArtifact(request);
- if (password == null) {
- this.logger.debug("Failed to obtain an artifact (cas ticket)");
- password = "";
- }
- UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
- authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
- return this.getAuthenticationManager().authenticate(authRequest);
- }
-
- /**
- * If present, gets the artifact (CAS ticket) from the {@link HttpServletRequest}.
- * @param request
- * @return if present the artifact from the {@link HttpServletRequest}, else null
- */
- protected String obtainArtifact(HttpServletRequest request) {
- return request.getParameter(this.artifactParameter);
- }
-
- /**
- * Overridden to provide proxying capabilities.
- */
- @Override
- protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
- final boolean serviceTicketRequest = serviceTicketRequest(request, response);
- final boolean result = serviceTicketRequest || proxyReceptorRequest(request)
- || (proxyTicketRequest(serviceTicketRequest, request));
- if (this.logger.isDebugEnabled()) {
- this.logger.debug("requiresAuthentication = " + result);
- }
- return result;
- }
-
- /**
- * Sets the {@link AuthenticationFailureHandler} for proxy requests.
- * @param proxyFailureHandler
- */
- public final void setProxyAuthenticationFailureHandler(AuthenticationFailureHandler proxyFailureHandler) {
- Assert.notNull(proxyFailureHandler, "proxyFailureHandler cannot be null");
- this.proxyFailureHandler = proxyFailureHandler;
- }
-
- /**
- * Wraps the {@link AuthenticationFailureHandler} to distinguish between handling
- * proxy ticket authentication failures and service ticket failures.
- */
- @Override
- public final void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
- super.setAuthenticationFailureHandler(new CasAuthenticationFailureHandler(failureHandler));
- }
-
- public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
- this.proxyReceptorMatcher = new AntPathRequestMatcher("/**" + proxyReceptorUrl);
- }
-
- public final void setProxyGrantingTicketStorage(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
- this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
- }
-
- public final void setServiceProperties(final ServiceProperties serviceProperties) {
- this.artifactParameter = serviceProperties.getArtifactParameter();
- this.authenticateAllArtifacts = serviceProperties.isAuthenticateAllArtifacts();
- }
-
- /**
- * Indicates if the request is elgible to process a service ticket. This method exists
- * for readability.
- * @param request
- * @param response
- * @return
- */
- private boolean serviceTicketRequest(HttpServletRequest request, HttpServletResponse response) {
- boolean result = super.requiresAuthentication(request, response);
- this.logger.debug(LogMessage.format("serviceTicketRequest = %s", result));
- return result;
- }
-
- /**
- * Indicates if the request is elgible to process a proxy ticket.
- * @param request
- * @return
- */
- private boolean proxyTicketRequest(boolean serviceTicketRequest, HttpServletRequest request) {
- if (serviceTicketRequest) {
- return false;
- }
- boolean result = this.authenticateAllArtifacts && obtainArtifact(request) != null && !authenticated();
- this.logger.debug(LogMessage.format("proxyTicketRequest = %s", result));
- return result;
- }
-
- /**
- * Determines if a user is already authenticated.
- * @return
- */
- private boolean authenticated() {
- Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
- return authentication != null && authentication.isAuthenticated()
- && !(authentication instanceof AnonymousAuthenticationToken);
- }
-
- /**
- * Indicates if the request is elgible to be processed as the proxy receptor.
- * @param request
- * @return
- */
- private boolean proxyReceptorRequest(HttpServletRequest request) {
- final boolean result = proxyReceptorConfigured() && this.proxyReceptorMatcher.matches(request);
- this.logger.debug(LogMessage.format("proxyReceptorRequest = %s", result));
- return result;
- }
-
- /**
- * Determines if the {@link CasAuthenticationFilter} is configured to handle the proxy
- * receptor requests.
- * @return
- */
- private boolean proxyReceptorConfigured() {
- final boolean result = this.proxyGrantingTicketStorage != null && this.proxyReceptorMatcher != null;
- this.logger.debug(LogMessage.format("proxyReceptorConfigured = %s", result));
- return result;
- }
-
- /**
- * A wrapper for the AuthenticationFailureHandler that will flex the
- * {@link AuthenticationFailureHandler} that is used. The value
- * {@link CasAuthenticationFilter#setProxyAuthenticationFailureHandler(AuthenticationFailureHandler)}
- * will be used for proxy requests that fail. The value
- * {@link CasAuthenticationFilter#setAuthenticationFailureHandler(AuthenticationFailureHandler)}
- * will be used for service tickets that fail.
- */
- private class CasAuthenticationFailureHandler implements AuthenticationFailureHandler {
-
- private final AuthenticationFailureHandler serviceTicketFailureHandler;
-
- CasAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
- Assert.notNull(failureHandler, "failureHandler");
- this.serviceTicketFailureHandler = failureHandler;
- }
-
- @Override
- public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
- AuthenticationException exception) throws IOException, ServletException {
- if (serviceTicketRequest(request, response)) {
- this.serviceTicketFailureHandler.onAuthenticationFailure(request, response, exception);
- }
- else {
- CasAuthenticationFilter.this.proxyFailureHandler.onAuthenticationFailure(request, response, exception);
- }
- }
-
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetails.java b/cas/src/main/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetails.java
deleted file mode 100644
index 2171df6cfcb..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetails.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2011-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.web.authentication;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.regex.Pattern;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.springframework.security.web.authentication.WebAuthenticationDetails;
-import org.springframework.security.web.util.UrlUtils;
-import org.springframework.util.Assert;
-
-/**
- * A default implementation of {@link ServiceAuthenticationDetails} that figures out the
- * value for {@link #getServiceUrl()} by inspecting the current {@link HttpServletRequest}
- * and using the current URL minus the artifact and the corresponding value.
- *
- * @author Rob Winch
- */
-final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
- implements ServiceAuthenticationDetails {
-
- private static final long serialVersionUID = 6192409090610517700L;
-
- private final String serviceUrl;
-
- /**
- * Creates a new instance
- * @param request the current {@link HttpServletRequest} to obtain the
- * {@link #getServiceUrl()} from.
- * @param artifactPattern the {@link Pattern} that will be used to clean up the query
- * string from containing the artifact name and value. This can be created using
- * {@link #createArtifactPattern(String)}.
- */
- DefaultServiceAuthenticationDetails(String casService, HttpServletRequest request, Pattern artifactPattern)
- throws MalformedURLException {
- super(request);
- URL casServiceUrl = new URL(casService);
- int port = getServicePort(casServiceUrl);
- final String query = getQueryString(request, artifactPattern);
- this.serviceUrl = UrlUtils.buildFullRequestUrl(casServiceUrl.getProtocol(), casServiceUrl.getHost(), port,
- request.getRequestURI(), query);
- }
-
- /**
- * Returns the current URL minus the artifact parameter and its value, if present.
- * @see org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails#getServiceUrl()
- */
- @Override
- public String getServiceUrl() {
- return this.serviceUrl;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails)) {
- return false;
- }
- ServiceAuthenticationDetails that = (ServiceAuthenticationDetails) obj;
- return this.serviceUrl.equals(that.getServiceUrl());
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
- result = prime * result + this.serviceUrl.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- StringBuilder result = new StringBuilder();
- result.append(super.toString());
- result.append("ServiceUrl: ");
- result.append(this.serviceUrl);
- return result.toString();
- }
-
- /**
- * If present, removes the artifactParameterName and the corresponding value from the
- * query String.
- * @param request
- * @return the query String minus the artifactParameterName and the corresponding
- * value.
- */
- private String getQueryString(final HttpServletRequest request, final Pattern artifactPattern) {
- final String query = request.getQueryString();
- if (query == null) {
- return null;
- }
- String result = artifactPattern.matcher(query).replaceFirst("");
- if (result.length() == 0) {
- return null;
- }
- // strip off the trailing & only if the artifact was the first query param
- return result.startsWith("&") ? result.substring(1) : result;
- }
-
- /**
- * Creates a {@link Pattern} that can be passed into the constructor. This allows the
- * {@link Pattern} to be reused for every instance of
- * {@link DefaultServiceAuthenticationDetails}.
- * @param artifactParameterName
- * @return
- */
- static Pattern createArtifactPattern(String artifactParameterName) {
- Assert.hasLength(artifactParameterName, "artifactParameterName is expected to have a length");
- return Pattern.compile("&?" + Pattern.quote(artifactParameterName) + "=[^&]*");
- }
-
- /**
- * Gets the port from the casServiceURL ensuring to return the proper value if the
- * default port is being used.
- * @param casServiceUrl the casServerUrl to be used (i.e.
- * "https://example.com/context/login/cas")
- * @return the port that is configured for the casServerUrl
- */
- private static int getServicePort(URL casServiceUrl) {
- int port = casServiceUrl.getPort();
- if (port == -1) {
- port = casServiceUrl.getDefaultPort();
- }
- return port;
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetails.java b/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetails.java
deleted file mode 100644
index e14da3d70e6..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetails.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2011-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.web.authentication;
-
-import java.io.Serializable;
-
-import org.springframework.security.cas.ServiceProperties;
-import org.springframework.security.cas.authentication.CasAuthenticationProvider;
-import org.springframework.security.core.Authentication;
-
-/**
- * In order for the {@link CasAuthenticationProvider} to provide the correct service url
- * to authenticate the ticket, the returned value of {@link Authentication#getDetails()}
- * should implement this interface when tickets can be sent to any URL rather than only
- * {@link ServiceProperties#getService()}.
- *
- * @author Rob Winch
- * @see ServiceAuthenticationDetailsSource
- */
-public interface ServiceAuthenticationDetails extends Serializable {
-
- /**
- * Gets the absolute service url (i.e. https://example.com/service/).
- * @return the service url. Cannot be null.
- */
- String getServiceUrl();
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetailsSource.java b/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetailsSource.java
deleted file mode 100644
index 375952373f5..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetailsSource.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2011-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.web.authentication;
-
-import java.net.MalformedURLException;
-import java.util.regex.Pattern;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.springframework.security.authentication.AuthenticationDetailsSource;
-import org.springframework.security.cas.ServiceProperties;
-import org.springframework.util.Assert;
-
-/**
- * The {@code AuthenticationDetailsSource} that is set on the
- * {@code CasAuthenticationFilter} should return a value that implements
- * {@code ServiceAuthenticationDetails} if the application needs to authenticate dynamic
- * service urls. The
- * {@code ServiceAuthenticationDetailsSource#buildDetails(HttpServletRequest)} creates a
- * default {@code ServiceAuthenticationDetails}.
- *
- * @author Rob Winch
- */
-public class ServiceAuthenticationDetailsSource
- implements AuthenticationDetailsSource {
-
- private final Pattern artifactPattern;
-
- private ServiceProperties serviceProperties;
-
- /**
- * Creates an implementation that uses the specified ServiceProperties and the default
- * CAS artifactParameterName.
- * @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
- */
- public ServiceAuthenticationDetailsSource(ServiceProperties serviceProperties) {
- this(serviceProperties, ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
- }
-
- /**
- * Creates an implementation that uses the specified artifactParameterName
- * @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
- * @param artifactParameterName the artifactParameterName that is removed from the
- * current URL. The result becomes the service url. Cannot be null and cannot be an
- * empty String.
- */
- public ServiceAuthenticationDetailsSource(ServiceProperties serviceProperties, String artifactParameterName) {
- Assert.notNull(serviceProperties, "serviceProperties cannot be null");
- this.serviceProperties = serviceProperties;
- this.artifactPattern = DefaultServiceAuthenticationDetails.createArtifactPattern(artifactParameterName);
- }
-
- /**
- * @param context the {@code HttpServletRequest} object.
- * @return the {@code ServiceAuthenticationDetails} containing information about the
- * current request
- */
- @Override
- public ServiceAuthenticationDetails buildDetails(HttpServletRequest context) {
- try {
- return new DefaultServiceAuthenticationDetails(this.serviceProperties.getService(), context,
- this.artifactPattern);
- }
- catch (MalformedURLException ex) {
- throw new RuntimeException(ex);
- }
- }
-
-}
diff --git a/cas/src/main/java/org/springframework/security/cas/web/authentication/package-info.java b/cas/src/main/java/org/springframework/security/cas/web/authentication/package-info.java
deleted file mode 100644
index ecd447dbac6..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/web/authentication/package-info.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2002-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Authentication processing mechanisms which respond to the submission of authentication
- * credentials using CAS.
- */
-package org.springframework.security.cas.web.authentication;
diff --git a/cas/src/main/java/org/springframework/security/cas/web/package-info.java b/cas/src/main/java/org/springframework/security/cas/web/package-info.java
deleted file mode 100644
index 903fdb8d4c0..00000000000
--- a/cas/src/main/java/org/springframework/security/cas/web/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2002-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Authenticates standard web browser users via CAS.
- */
-package org.springframework.security.cas.web;
diff --git a/cas/src/test/java/org/springframework/security/cas/authentication/AbstractStatelessTicketCacheTests.java b/cas/src/test/java/org/springframework/security/cas/authentication/AbstractStatelessTicketCacheTests.java
deleted file mode 100644
index 7f1233b7d5f..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/authentication/AbstractStatelessTicketCacheTests.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2002-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.jasig.cas.client.validation.Assertion;
-import org.jasig.cas.client.validation.AssertionImpl;
-
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.userdetails.User;
-
-/**
- * @author Scott Battaglia
- * @since 2.0
- *
- */
-public abstract class AbstractStatelessTicketCacheTests {
-
- protected CasAuthenticationToken getToken() {
- List proxyList = new ArrayList<>();
- proxyList.add("https://localhost/newPortal/login/cas");
- User user = new User("rod", "password", true, true, true, true,
- AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"));
- final Assertion assertion = new AssertionImpl("rod");
- return new CasAuthenticationToken("key", user, "ST-0-ER94xMJmn6pha35CQRoZ",
- AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"), user, assertion);
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/authentication/CasAuthenticationProviderTests.java b/cas/src/test/java/org/springframework/security/cas/authentication/CasAuthenticationProviderTests.java
deleted file mode 100644
index 242d32a730d..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/authentication/CasAuthenticationProviderTests.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.jasig.cas.client.validation.Assertion;
-import org.jasig.cas.client.validation.AssertionImpl;
-import org.jasig.cas.client.validation.TicketValidator;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.TestingAuthenticationToken;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.cas.ServiceProperties;
-import org.springframework.security.cas.web.CasAuthenticationFilter;
-import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.web.authentication.WebAuthenticationDetails;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
-import static org.assertj.core.api.Assertions.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-/**
- * Tests {@link CasAuthenticationProvider}.
- *
- * @author Ben Alex
- * @author Scott Battaglia
- */
-@SuppressWarnings("unchecked")
-public class CasAuthenticationProviderTests {
-
- private UserDetails makeUserDetails() {
- return new User("user", "password", true, true, true, true,
- AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"));
- }
-
- private UserDetails makeUserDetailsFromAuthoritiesPopulator() {
- return new User("user", "password", true, true, true, true,
- AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B"));
- }
-
- private ServiceProperties makeServiceProperties() {
- final ServiceProperties serviceProperties = new ServiceProperties();
- serviceProperties.setSendRenew(false);
- serviceProperties.setService("http://test.com");
- return serviceProperties;
- }
-
- @Test
- public void statefulAuthenticationIsSuccessful() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- StatelessTicketCache cache = new MockStatelessTicketCache();
- cap.setStatelessTicketCache(cache);
- cap.setServiceProperties(makeServiceProperties());
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.afterPropertiesSet();
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
- CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "ST-123");
- token.setDetails("details");
- Authentication result = cap.authenticate(token);
- // Confirm ST-123 was NOT added to the cache
- assertThat(cache.getByTicketId("ST-456") == null).isTrue();
- if (!(result instanceof CasAuthenticationToken)) {
- fail("Should have returned a CasAuthenticationToken");
- }
- CasAuthenticationToken casResult = (CasAuthenticationToken) result;
- assertThat(casResult.getPrincipal()).isEqualTo(makeUserDetailsFromAuthoritiesPopulator());
- assertThat(casResult.getCredentials()).isEqualTo("ST-123");
- assertThat(casResult.getAuthorities()).contains(new SimpleGrantedAuthority("ROLE_A"));
- assertThat(casResult.getAuthorities()).contains(new SimpleGrantedAuthority("ROLE_B"));
- assertThat(casResult.getKeyHash()).isEqualTo(cap.getKey().hashCode());
- assertThat(casResult.getDetails()).isEqualTo("details");
- // Now confirm the CasAuthenticationToken is automatically re-accepted.
- // To ensure TicketValidator not called again, set it to deliver an exception...
- cap.setTicketValidator(new MockTicketValidator(false));
- Authentication laterResult = cap.authenticate(result);
- assertThat(laterResult).isEqualTo(result);
- }
-
- @Test
- public void statelessAuthenticationIsSuccessful() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- StatelessTicketCache cache = new MockStatelessTicketCache();
- cap.setStatelessTicketCache(cache);
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.setServiceProperties(makeServiceProperties());
- cap.afterPropertiesSet();
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
- CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, "ST-456");
- token.setDetails("details");
- Authentication result = cap.authenticate(token);
- // Confirm ST-456 was added to the cache
- assertThat(cache.getByTicketId("ST-456") != null).isTrue();
- if (!(result instanceof CasAuthenticationToken)) {
- fail("Should have returned a CasAuthenticationToken");
- }
- assertThat(result.getPrincipal()).isEqualTo(makeUserDetailsFromAuthoritiesPopulator());
- assertThat(result.getCredentials()).isEqualTo("ST-456");
- assertThat(result.getDetails()).isEqualTo("details");
- // Now try to authenticate again. To ensure TicketValidator not
- // called again, set it to deliver an exception...
- cap.setTicketValidator(new MockTicketValidator(false));
- // Previously created UsernamePasswordAuthenticationToken is OK
- Authentication newResult = cap.authenticate(token);
- assertThat(newResult.getPrincipal()).isEqualTo(makeUserDetailsFromAuthoritiesPopulator());
- assertThat(newResult.getCredentials()).isEqualTo("ST-456");
- }
-
- @Test
- public void authenticateAllNullService() throws Exception {
- String serviceUrl = "https://service/context";
- ServiceAuthenticationDetails details = mock(ServiceAuthenticationDetails.class);
- given(details.getServiceUrl()).willReturn(serviceUrl);
- TicketValidator validator = mock(TicketValidator.class);
- given(validator.validate(any(String.class), any(String.class))).willReturn(new AssertionImpl("rod"));
- ServiceProperties serviceProperties = makeServiceProperties();
- serviceProperties.setAuthenticateAllArtifacts(true);
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- cap.setTicketValidator(validator);
- cap.setServiceProperties(serviceProperties);
- cap.afterPropertiesSet();
- String ticket = "ST-456";
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
- CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
- Authentication result = cap.authenticate(token);
- }
-
- @Test
- public void authenticateAllAuthenticationIsSuccessful() throws Exception {
- String serviceUrl = "https://service/context";
- ServiceAuthenticationDetails details = mock(ServiceAuthenticationDetails.class);
- given(details.getServiceUrl()).willReturn(serviceUrl);
- TicketValidator validator = mock(TicketValidator.class);
- given(validator.validate(any(String.class), any(String.class))).willReturn(new AssertionImpl("rod"));
- ServiceProperties serviceProperties = makeServiceProperties();
- serviceProperties.setAuthenticateAllArtifacts(true);
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- cap.setTicketValidator(validator);
- cap.setServiceProperties(serviceProperties);
- cap.afterPropertiesSet();
- String ticket = "ST-456";
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
- CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
- Authentication result = cap.authenticate(token);
- verify(validator).validate(ticket, serviceProperties.getService());
- serviceProperties.setAuthenticateAllArtifacts(true);
- result = cap.authenticate(token);
- verify(validator, times(2)).validate(ticket, serviceProperties.getService());
- token.setDetails(details);
- result = cap.authenticate(token);
- verify(validator).validate(ticket, serviceUrl);
- serviceProperties.setAuthenticateAllArtifacts(false);
- serviceProperties.setService(null);
- cap.setServiceProperties(serviceProperties);
- cap.afterPropertiesSet();
- result = cap.authenticate(token);
- verify(validator, times(2)).validate(ticket, serviceUrl);
- token.setDetails(new WebAuthenticationDetails(new MockHttpServletRequest()));
- assertThatIllegalStateException().isThrownBy(() -> cap.authenticate(token));
- cap.setServiceProperties(null);
- cap.afterPropertiesSet();
- assertThatIllegalStateException().isThrownBy(() -> cap.authenticate(token));
- }
-
- @Test
- public void missingTicketIdIsDetected() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- StatelessTicketCache cache = new MockStatelessTicketCache();
- cap.setStatelessTicketCache(cache);
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.setServiceProperties(makeServiceProperties());
- cap.afterPropertiesSet();
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
- CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "");
- assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> cap.authenticate(token));
- }
-
- @Test
- public void invalidKeyIsDetected() throws Exception {
- final Assertion assertion = new AssertionImpl("test");
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- StatelessTicketCache cache = new MockStatelessTicketCache();
- cap.setStatelessTicketCache(cache);
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.setServiceProperties(makeServiceProperties());
- cap.afterPropertiesSet();
- CasAuthenticationToken token = new CasAuthenticationToken("WRONG_KEY", makeUserDetails(), "credentials",
- AuthorityUtils.createAuthorityList("XX"), makeUserDetails(), assertion);
- assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> cap.authenticate(token));
- }
-
- @Test
- public void detectsMissingAuthoritiesPopulator() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setKey("qwerty");
- cap.setStatelessTicketCache(new MockStatelessTicketCache());
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.setServiceProperties(makeServiceProperties());
- assertThatIllegalArgumentException().isThrownBy(() -> cap.afterPropertiesSet());
- }
-
- @Test
- public void detectsMissingKey() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setStatelessTicketCache(new MockStatelessTicketCache());
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.setServiceProperties(makeServiceProperties());
- assertThatIllegalArgumentException().isThrownBy(() -> cap.afterPropertiesSet());
- }
-
- @Test
- public void detectsMissingStatelessTicketCache() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- // set this explicitly to null to test failure
- cap.setStatelessTicketCache(null);
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.setServiceProperties(makeServiceProperties());
- assertThatIllegalArgumentException().isThrownBy(() -> cap.afterPropertiesSet());
- }
-
- @Test
- public void detectsMissingTicketValidator() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- cap.setStatelessTicketCache(new MockStatelessTicketCache());
- cap.setServiceProperties(makeServiceProperties());
- assertThatIllegalArgumentException().isThrownBy(() -> cap.afterPropertiesSet());
- }
-
- @Test
- public void gettersAndSettersMatch() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- cap.setStatelessTicketCache(new MockStatelessTicketCache());
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.setServiceProperties(makeServiceProperties());
- cap.afterPropertiesSet();
- // TODO disabled because why do we need to expose this?
- // assertThat(cap.getUserDetailsService() != null).isTrue();
- assertThat(cap.getKey()).isEqualTo("qwerty");
- assertThat(cap.getStatelessTicketCache() != null).isTrue();
- assertThat(cap.getTicketValidator() != null).isTrue();
- }
-
- @Test
- public void ignoresClassesItDoesNotSupport() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- cap.setStatelessTicketCache(new MockStatelessTicketCache());
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.setServiceProperties(makeServiceProperties());
- cap.afterPropertiesSet();
- TestingAuthenticationToken token = new TestingAuthenticationToken("user", "password", "ROLE_A");
- assertThat(cap.supports(TestingAuthenticationToken.class)).isFalse();
- // Try it anyway
- assertThat(cap.authenticate(token)).isNull();
- }
-
- @Test
- public void ignoresUsernamePasswordAuthenticationTokensWithoutCasIdentifiersAsPrincipal() throws Exception {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
- cap.setKey("qwerty");
- cap.setStatelessTicketCache(new MockStatelessTicketCache());
- cap.setTicketValidator(new MockTicketValidator(true));
- cap.setServiceProperties(makeServiceProperties());
- cap.afterPropertiesSet();
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("some_normal_user",
- "password", AuthorityUtils.createAuthorityList("ROLE_A"));
- assertThat(cap.authenticate(token)).isNull();
- }
-
- @Test
- public void supportsRequiredTokens() {
- CasAuthenticationProvider cap = new CasAuthenticationProvider();
- assertThat(cap.supports(UsernamePasswordAuthenticationToken.class)).isTrue();
- assertThat(cap.supports(CasAuthenticationToken.class)).isTrue();
- }
-
- private class MockAuthoritiesPopulator implements AuthenticationUserDetailsService {
-
- @Override
- public UserDetails loadUserDetails(final Authentication token) throws UsernameNotFoundException {
- return makeUserDetailsFromAuthoritiesPopulator();
- }
-
- }
-
- private class MockStatelessTicketCache implements StatelessTicketCache {
-
- private Map cache = new HashMap<>();
-
- @Override
- public CasAuthenticationToken getByTicketId(String serviceTicket) {
- return this.cache.get(serviceTicket);
- }
-
- @Override
- public void putTicketInCache(CasAuthenticationToken token) {
- this.cache.put(token.getCredentials().toString(), token);
- }
-
- @Override
- public void removeTicketFromCache(CasAuthenticationToken token) {
- throw new UnsupportedOperationException("mock method not implemented");
- }
-
- @Override
- public void removeTicketFromCache(String serviceTicket) {
- throw new UnsupportedOperationException("mock method not implemented");
- }
-
- }
-
- private class MockTicketValidator implements TicketValidator {
-
- private boolean returnTicket;
-
- MockTicketValidator(boolean returnTicket) {
- this.returnTicket = returnTicket;
- }
-
- @Override
- public Assertion validate(final String ticket, final String service) {
- if (this.returnTicket) {
- return new AssertionImpl("rod");
- }
- throw new BadCredentialsException("As requested from mock");
- }
-
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/authentication/CasAuthenticationTokenTests.java b/cas/src/test/java/org/springframework/security/cas/authentication/CasAuthenticationTokenTests.java
deleted file mode 100644
index 8ac076830be..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/authentication/CasAuthenticationTokenTests.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import java.util.Collections;
-import java.util.List;
-
-import org.jasig.cas.client.validation.Assertion;
-import org.jasig.cas.client.validation.AssertionImpl;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-
-/**
- * Tests {@link CasAuthenticationToken}.
- *
- * @author Ben Alex
- */
-public class CasAuthenticationTokenTests {
-
- private final List ROLES = AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO");
-
- private UserDetails makeUserDetails() {
- return makeUserDetails("user");
- }
-
- private UserDetails makeUserDetails(final String name) {
- return new User(name, "password", true, true, true, true, this.ROLES);
- }
-
- @Test
- public void testConstructorRejectsNulls() {
- Assertion assertion = new AssertionImpl("test");
- assertThatIllegalArgumentException().isThrownBy(() -> new CasAuthenticationToken(null, makeUserDetails(),
- "Password", this.ROLES, makeUserDetails(), assertion));
- assertThatIllegalArgumentException().isThrownBy(
- () -> new CasAuthenticationToken("key", null, "Password", this.ROLES, makeUserDetails(), assertion));
- assertThatIllegalArgumentException().isThrownBy(() -> new CasAuthenticationToken("key", makeUserDetails(), null,
- this.ROLES, makeUserDetails(), assertion));
- assertThatIllegalArgumentException().isThrownBy(() -> new CasAuthenticationToken("key", makeUserDetails(),
- "Password", this.ROLES, makeUserDetails(), null));
- assertThatIllegalArgumentException().isThrownBy(
- () -> new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES, null, assertion));
- assertThatIllegalArgumentException().isThrownBy(() -> new CasAuthenticationToken("key", makeUserDetails(),
- "Password", AuthorityUtils.createAuthorityList("ROLE_1", null), makeUserDetails(), assertion));
- }
-
- @Test
- public void constructorWhenEmptyKeyThenThrowsException() {
- assertThatIllegalArgumentException().isThrownBy(
- () -> new CasAuthenticationToken("", "user", "password", Collections.emptyList(),
- new User("user", "password", Collections.emptyList()), null));
- }
-
- @Test
- public void testEqualsWhenEqual() {
- final Assertion assertion = new AssertionImpl("test");
- CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion);
- CasAuthenticationToken token2 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion);
- assertThat(token2).isEqualTo(token1);
- }
-
- @Test
- public void testGetters() {
- // Build the proxy list returned in the ticket from CAS
- final Assertion assertion = new AssertionImpl("test");
- CasAuthenticationToken token = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion);
- assertThat(token.getKeyHash()).isEqualTo("key".hashCode());
- assertThat(token.getPrincipal()).isEqualTo(makeUserDetails());
- assertThat(token.getCredentials()).isEqualTo("Password");
- assertThat(token.getAuthorities()).contains(new SimpleGrantedAuthority("ROLE_ONE"));
- assertThat(token.getAuthorities()).contains(new SimpleGrantedAuthority("ROLE_TWO"));
- assertThat(token.getAssertion()).isEqualTo(assertion);
- assertThat(token.getUserDetails().getUsername()).isEqualTo(makeUserDetails().getUsername());
- }
-
- @Test
- public void testNoArgConstructorDoesntExist() {
- assertThatExceptionOfType(NoSuchMethodException.class)
- .isThrownBy(() -> CasAuthenticationToken.class.getDeclaredConstructor((Class[]) null));
- }
-
- @Test
- public void testNotEqualsDueToAbstractParentEqualsCheck() {
- final Assertion assertion = new AssertionImpl("test");
- CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion);
- CasAuthenticationToken token2 = new CasAuthenticationToken("key", makeUserDetails("OTHER_NAME"), "Password",
- this.ROLES, makeUserDetails(), assertion);
- assertThat(!token1.equals(token2)).isTrue();
- }
-
- @Test
- public void testNotEqualsDueToDifferentAuthenticationClass() {
- final Assertion assertion = new AssertionImpl("test");
- CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion);
- UsernamePasswordAuthenticationToken token2 = new UsernamePasswordAuthenticationToken("Test", "Password",
- this.ROLES);
- assertThat(!token1.equals(token2)).isTrue();
- }
-
- @Test
- public void testNotEqualsDueToKey() {
- final Assertion assertion = new AssertionImpl("test");
- CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion);
- CasAuthenticationToken token2 = new CasAuthenticationToken("DIFFERENT_KEY", makeUserDetails(), "Password",
- this.ROLES, makeUserDetails(), assertion);
- assertThat(!token1.equals(token2)).isTrue();
- }
-
- @Test
- public void testNotEqualsDueToAssertion() {
- final Assertion assertion = new AssertionImpl("test");
- final Assertion assertion2 = new AssertionImpl("test");
- CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion);
- CasAuthenticationToken token2 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion2);
- assertThat(!token1.equals(token2)).isTrue();
- }
-
- @Test
- public void testSetAuthenticated() {
- final Assertion assertion = new AssertionImpl("test");
- CasAuthenticationToken token = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion);
- assertThat(token.isAuthenticated()).isTrue();
- token.setAuthenticated(false);
- assertThat(!token.isAuthenticated()).isTrue();
- }
-
- @Test
- public void testToString() {
- final Assertion assertion = new AssertionImpl("test");
- CasAuthenticationToken token = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
- makeUserDetails(), assertion);
- String result = token.toString();
- assertThat(result.lastIndexOf("Credentials (Service/Proxy Ticket):") != -1).isTrue();
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/authentication/EhCacheBasedTicketCacheTests.java b/cas/src/test/java/org/springframework/security/cas/authentication/EhCacheBasedTicketCacheTests.java
deleted file mode 100644
index c824eef4bc6..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/authentication/EhCacheBasedTicketCacheTests.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import net.sf.ehcache.Cache;
-import net.sf.ehcache.CacheManager;
-import net.sf.ehcache.Ehcache;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-
-/**
- * Tests {@link EhCacheBasedTicketCache}.
- *
- * @author Ben Alex
- */
-public class EhCacheBasedTicketCacheTests extends AbstractStatelessTicketCacheTests {
-
- private static CacheManager cacheManager;
-
- @BeforeAll
- public static void initCacheManaer() {
- cacheManager = CacheManager.create();
- cacheManager.addCache(new Cache("castickets", 500, false, false, 30, 30));
- }
-
- @AfterAll
- public static void shutdownCacheManager() {
- cacheManager.removalAll();
- cacheManager.shutdown();
- }
-
- @Test
- public void testCacheOperation() throws Exception {
- EhCacheBasedTicketCache cache = new EhCacheBasedTicketCache();
- cache.setCache(cacheManager.getCache("castickets"));
- cache.afterPropertiesSet();
- final CasAuthenticationToken token = getToken();
- // Check it gets stored in the cache
- cache.putTicketInCache(token);
- assertThat(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ")).isEqualTo(token);
- // Check it gets removed from the cache
- cache.removeTicketFromCache(getToken());
- assertThat(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ")).isNull();
- // Check it doesn't return values for null or unknown service tickets
- assertThat(cache.getByTicketId(null)).isNull();
- assertThat(cache.getByTicketId("UNKNOWN_SERVICE_TICKET")).isNull();
- }
-
- @Test
- public void testStartupDetectsMissingCache() throws Exception {
- EhCacheBasedTicketCache cache = new EhCacheBasedTicketCache();
- assertThatIllegalArgumentException().isThrownBy(cache::afterPropertiesSet);
- Ehcache myCache = cacheManager.getCache("castickets");
- cache.setCache(myCache);
- assertThat(cache.getCache()).isEqualTo(myCache);
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/authentication/NullStatelessTicketCacheTests.java b/cas/src/test/java/org/springframework/security/cas/authentication/NullStatelessTicketCacheTests.java
deleted file mode 100644
index f5a87e5c4e9..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/authentication/NullStatelessTicketCacheTests.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Test cases for the @link {@link NullStatelessTicketCache}
- *
- * @author Scott Battaglia
- *
- */
-public class NullStatelessTicketCacheTests extends AbstractStatelessTicketCacheTests {
-
- private StatelessTicketCache cache = new NullStatelessTicketCache();
-
- @Test
- public void testGetter() {
- assertThat(this.cache.getByTicketId(null)).isNull();
- assertThat(this.cache.getByTicketId("test")).isNull();
- }
-
- @Test
- public void testInsertAndGet() {
- final CasAuthenticationToken token = getToken();
- this.cache.putTicketInCache(token);
- assertThat(this.cache.getByTicketId((String) token.getCredentials())).isNull();
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/authentication/SpringCacheBasedTicketCacheTests.java b/cas/src/test/java/org/springframework/security/cas/authentication/SpringCacheBasedTicketCacheTests.java
deleted file mode 100644
index e27344a9ce6..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/authentication/SpringCacheBasedTicketCacheTests.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.authentication;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.cache.CacheManager;
-import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-
-/**
- * Tests
- * {@link org.springframework.security.cas.authentication.SpringCacheBasedTicketCache}.
- *
- * @author Marten Deinum
- * @since 3.2
- */
-public class SpringCacheBasedTicketCacheTests extends AbstractStatelessTicketCacheTests {
-
- private static CacheManager cacheManager;
-
- @BeforeAll
- public static void initCacheManaer() {
- cacheManager = new ConcurrentMapCacheManager();
- cacheManager.getCache("castickets");
- }
-
- @Test
- public void testCacheOperation() throws Exception {
- SpringCacheBasedTicketCache cache = new SpringCacheBasedTicketCache(cacheManager.getCache("castickets"));
- final CasAuthenticationToken token = getToken();
- // Check it gets stored in the cache
- cache.putTicketInCache(token);
- assertThat(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ")).isEqualTo(token);
- // Check it gets removed from the cache
- cache.removeTicketFromCache(getToken());
- assertThat(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ")).isNull();
- // Check it doesn't return values for null or unknown service tickets
- assertThat(cache.getByTicketId(null)).isNull();
- assertThat(cache.getByTicketId("UNKNOWN_SERVICE_TICKET")).isNull();
- }
-
- @Test
- public void testStartupDetectsMissingCache() throws Exception {
- assertThatIllegalArgumentException().isThrownBy(() -> new SpringCacheBasedTicketCache(null));
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/jackson2/CasAuthenticationTokenMixinTests.java b/cas/src/test/java/org/springframework/security/cas/jackson2/CasAuthenticationTokenMixinTests.java
deleted file mode 100644
index ce333d4d83f..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/jackson2/CasAuthenticationTokenMixinTests.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2015-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.jackson2;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.jasig.cas.client.authentication.AttributePrincipalImpl;
-import org.jasig.cas.client.validation.Assertion;
-import org.jasig.cas.client.validation.AssertionImpl;
-import org.json.JSONException;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.skyscreamer.jsonassert.JSONAssert;
-
-import org.springframework.security.cas.authentication.CasAuthenticationToken;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.jackson2.SecurityJackson2Modules;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * @author Jitendra Singh
- * @since 4.2
- */
-public class CasAuthenticationTokenMixinTests {
-
- private static final String KEY = "casKey";
-
- private static final String PASSWORD = "\"1234\"";
-
- private static final Date START_DATE = new Date();
-
- private static final Date END_DATE = new Date();
-
- public static final String AUTHORITY_JSON = "{\"@class\": \"org.springframework.security.core.authority.SimpleGrantedAuthority\", \"authority\": \"ROLE_USER\"}";
-
- public static final String AUTHORITIES_SET_JSON = "[\"java.util.Collections$UnmodifiableSet\", [" + AUTHORITY_JSON
- + "]]";
-
- public static final String AUTHORITIES_ARRAYLIST_JSON = "[\"java.util.Collections$UnmodifiableRandomAccessList\", ["
- + AUTHORITY_JSON + "]]";
-
- // @formatter:off
- public static final String USER_JSON = "{"
- + "\"@class\": \"org.springframework.security.core.userdetails.User\", "
- + "\"username\": \"admin\","
- + " \"password\": " + PASSWORD + ", "
- + "\"accountNonExpired\": true, "
- + "\"accountNonLocked\": true, "
- + "\"credentialsNonExpired\": true, "
- + "\"enabled\": true, "
- + "\"authorities\": " + AUTHORITIES_SET_JSON
- + "}";
- // @formatter:on
- private static final String CAS_TOKEN_JSON = "{"
- + "\"@class\": \"org.springframework.security.cas.authentication.CasAuthenticationToken\", "
- + "\"keyHash\": " + KEY.hashCode() + "," + "\"principal\": " + USER_JSON + ", " + "\"credentials\": "
- + PASSWORD + ", " + "\"authorities\": " + AUTHORITIES_ARRAYLIST_JSON + "," + "\"userDetails\": " + USER_JSON
- + "," + "\"authenticated\": true, " + "\"details\": null," + "\"assertion\": {"
- + "\"@class\": \"org.jasig.cas.client.validation.AssertionImpl\", " + "\"principal\": {"
- + "\"@class\": \"org.jasig.cas.client.authentication.AttributePrincipalImpl\", "
- + "\"name\": \"assertName\", " + "\"attributes\": {\"@class\": \"java.util.Collections$EmptyMap\"}, "
- + "\"proxyGrantingTicket\": null, " + "\"proxyRetriever\": null" + "}, "
- + "\"validFromDate\": [\"java.util.Date\", " + START_DATE.getTime() + "], "
- + "\"validUntilDate\": [\"java.util.Date\", " + END_DATE.getTime() + "],"
- + "\"authenticationDate\": [\"java.util.Date\", " + START_DATE.getTime() + "], "
- + "\"attributes\": {\"@class\": \"java.util.Collections$EmptyMap\"}" + "}" + "}";
-
- private static final String CAS_TOKEN_CLEARED_JSON = CAS_TOKEN_JSON.replaceFirst(PASSWORD, "null");
-
- protected ObjectMapper mapper;
-
- @BeforeEach
- public void setup() {
- this.mapper = new ObjectMapper();
- ClassLoader loader = getClass().getClassLoader();
- this.mapper.registerModules(SecurityJackson2Modules.getModules(loader));
- }
-
- @Test
- public void serializeCasAuthenticationTest() throws JsonProcessingException, JSONException {
- CasAuthenticationToken token = createCasAuthenticationToken();
- String actualJson = this.mapper.writeValueAsString(token);
- JSONAssert.assertEquals(CAS_TOKEN_JSON, actualJson, true);
- }
-
- @Test
- public void serializeCasAuthenticationTestAfterEraseCredentialInvoked()
- throws JsonProcessingException, JSONException {
- CasAuthenticationToken token = createCasAuthenticationToken();
- token.eraseCredentials();
- String actualJson = this.mapper.writeValueAsString(token);
- JSONAssert.assertEquals(CAS_TOKEN_CLEARED_JSON, actualJson, true);
- }
-
- @Test
- public void deserializeCasAuthenticationTestAfterEraseCredentialInvoked() throws Exception {
- CasAuthenticationToken token = this.mapper.readValue(CAS_TOKEN_CLEARED_JSON, CasAuthenticationToken.class);
- assertThat(((UserDetails) token.getPrincipal()).getPassword()).isNull();
- }
-
- @Test
- public void deserializeCasAuthenticationTest() throws IOException {
- CasAuthenticationToken token = this.mapper.readValue(CAS_TOKEN_JSON, CasAuthenticationToken.class);
- assertThat(token).isNotNull();
- assertThat(token.getPrincipal()).isNotNull().isInstanceOf(User.class);
- assertThat(((User) token.getPrincipal()).getUsername()).isEqualTo("admin");
- assertThat(((User) token.getPrincipal()).getPassword()).isEqualTo("1234");
- assertThat(token.getUserDetails()).isNotNull().isInstanceOf(User.class);
- assertThat(token.getAssertion()).isNotNull().isInstanceOf(AssertionImpl.class);
- assertThat(token.getKeyHash()).isEqualTo(KEY.hashCode());
- assertThat(token.getUserDetails().getAuthorities()).extracting(GrantedAuthority::getAuthority)
- .containsOnly("ROLE_USER");
- assertThat(token.getAssertion().getAuthenticationDate()).isEqualTo(START_DATE);
- assertThat(token.getAssertion().getValidFromDate()).isEqualTo(START_DATE);
- assertThat(token.getAssertion().getValidUntilDate()).isEqualTo(END_DATE);
- assertThat(token.getAssertion().getPrincipal().getName()).isEqualTo("assertName");
- assertThat(token.getAssertion().getAttributes()).hasSize(0);
- }
-
- private CasAuthenticationToken createCasAuthenticationToken() {
- User principal = new User("admin", "1234", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
- Collection extends GrantedAuthority> authorities = Collections
- .singletonList(new SimpleGrantedAuthority("ROLE_USER"));
- Assertion assertion = new AssertionImpl(new AttributePrincipalImpl("assertName"), START_DATE, END_DATE,
- START_DATE, Collections.emptyMap());
- return new CasAuthenticationToken(KEY, principal, principal.getPassword(), authorities,
- new User("admin", "1234", authorities), assertion);
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/userdetails/GrantedAuthorityFromAssertionAttributesUserDetailsServiceTests.java b/cas/src/test/java/org/springframework/security/cas/userdetails/GrantedAuthorityFromAssertionAttributesUserDetailsServiceTests.java
deleted file mode 100644
index 3db719dcc28..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/userdetails/GrantedAuthorityFromAssertionAttributesUserDetailsServiceTests.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.userdetails;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.jasig.cas.client.authentication.AttributePrincipal;
-import org.jasig.cas.client.validation.Assertion;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.userdetails.UserDetails;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
-
-/**
- * @author Luke Taylor
- */
-public class GrantedAuthorityFromAssertionAttributesUserDetailsServiceTests {
-
- @Test
- public void correctlyExtractsNamedAttributesFromAssertionAndConvertsThemToAuthorities() {
- GrantedAuthorityFromAssertionAttributesUserDetailsService uds = new GrantedAuthorityFromAssertionAttributesUserDetailsService(
- new String[] { "a", "b", "c", "d" });
- uds.setConvertToUpperCase(false);
- Assertion assertion = mock(Assertion.class);
- AttributePrincipal principal = mock(AttributePrincipal.class);
- Map attributes = new HashMap<>();
- attributes.put("a", Arrays.asList("role_a1", "role_a2"));
- attributes.put("b", "role_b");
- attributes.put("c", "role_c");
- attributes.put("d", null);
- attributes.put("someother", "unused");
- given(assertion.getPrincipal()).willReturn(principal);
- given(principal.getAttributes()).willReturn(attributes);
- given(principal.getName()).willReturn("somebody");
- CasAssertionAuthenticationToken token = new CasAssertionAuthenticationToken(assertion, "ticket");
- UserDetails user = uds.loadUserDetails(token);
- Set roles = AuthorityUtils.authorityListToSet(user.getAuthorities());
- assertThat(roles).containsExactlyInAnyOrder("role_a1", "role_a2", "role_b", "role_c");
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationEntryPointTests.java b/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationEntryPointTests.java
deleted file mode 100644
index 5fb0e7c7f8c..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationEntryPointTests.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.web;
-
-import java.net.URLEncoder;
-
-import org.junit.jupiter.api.Test;
-
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.mock.web.MockHttpServletResponse;
-import org.springframework.security.cas.ServiceProperties;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-
-/**
- * Tests {@link CasAuthenticationEntryPoint}.
- *
- * @author Ben Alex
- */
-public class CasAuthenticationEntryPointTests {
-
- @Test
- public void testDetectsMissingLoginFormUrl() throws Exception {
- CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
- ep.setServiceProperties(new ServiceProperties());
- assertThatIllegalArgumentException().isThrownBy(ep::afterPropertiesSet)
- .withMessage("loginUrl must be specified");
- }
-
- @Test
- public void testDetectsMissingServiceProperties() throws Exception {
- CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
- ep.setLoginUrl("https://cas/login");
- assertThatIllegalArgumentException().isThrownBy(ep::afterPropertiesSet)
- .withMessage("serviceProperties must be specified");
- }
-
- @Test
- public void testGettersSetters() {
- CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
- ep.setLoginUrl("https://cas/login");
- assertThat(ep.getLoginUrl()).isEqualTo("https://cas/login");
- ep.setServiceProperties(new ServiceProperties());
- assertThat(ep.getServiceProperties() != null).isTrue();
- }
-
- @Test
- public void testNormalOperationWithRenewFalse() throws Exception {
- ServiceProperties sp = new ServiceProperties();
- sp.setSendRenew(false);
- sp.setService("https://mycompany.com/bigWebApp/login/cas");
- CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
- ep.setLoginUrl("https://cas/login");
- ep.setServiceProperties(sp);
- MockHttpServletRequest request = new MockHttpServletRequest();
- request.setRequestURI("/some_path");
- MockHttpServletResponse response = new MockHttpServletResponse();
- ep.afterPropertiesSet();
- ep.commence(request, response, null);
- assertThat(
- "https://cas/login?service=" + URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8"))
- .isEqualTo(response.getRedirectedUrl());
- }
-
- @Test
- public void testNormalOperationWithRenewTrue() throws Exception {
- ServiceProperties sp = new ServiceProperties();
- sp.setSendRenew(true);
- sp.setService("https://mycompany.com/bigWebApp/login/cas");
- CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
- ep.setLoginUrl("https://cas/login");
- ep.setServiceProperties(sp);
- MockHttpServletRequest request = new MockHttpServletRequest();
- request.setRequestURI("/some_path");
- MockHttpServletResponse response = new MockHttpServletResponse();
- ep.afterPropertiesSet();
- ep.commence(request, response, null);
- assertThat("https://cas/login?service="
- + URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8") + "&renew=true")
- .isEqualTo(response.getRedirectedUrl());
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationFilterTests.java b/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationFilterTests.java
deleted file mode 100644
index fab4d2ed1d9..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationFilterTests.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.web;
-
-import javax.servlet.FilterChain;
-
-import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.mock.web.MockHttpServletResponse;
-import org.springframework.security.authentication.AnonymousAuthenticationToken;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.TestingAuthenticationToken;
-import org.springframework.security.cas.ServiceProperties;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-/**
- * Tests {@link CasAuthenticationFilter}.
- *
- * @author Ben Alex
- * @author Rob Winch
- */
-public class CasAuthenticationFilterTests {
-
- @AfterEach
- public void tearDown() {
- SecurityContextHolder.clearContext();
- }
-
- @Test
- public void testGettersSetters() {
- CasAuthenticationFilter filter = new CasAuthenticationFilter();
- filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
- filter.setProxyReceptorUrl("/someurl");
- filter.setServiceProperties(new ServiceProperties());
- }
-
- @Test
- public void testNormalOperation() throws Exception {
- MockHttpServletRequest request = new MockHttpServletRequest();
- request.setServletPath("/login/cas");
- request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
- CasAuthenticationFilter filter = new CasAuthenticationFilter();
- filter.setAuthenticationManager((a) -> a);
- assertThat(filter.requiresAuthentication(request, new MockHttpServletResponse())).isTrue();
- Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
- assertThat(result != null).isTrue();
- }
-
- @Test
- public void testNullServiceTicketHandledGracefully() throws Exception {
- CasAuthenticationFilter filter = new CasAuthenticationFilter();
- filter.setAuthenticationManager((a) -> {
- throw new BadCredentialsException("Rejected");
- });
- assertThatExceptionOfType(AuthenticationException.class).isThrownBy(
- () -> filter.attemptAuthentication(new MockHttpServletRequest(), new MockHttpServletResponse()));
- }
-
- @Test
- public void testRequiresAuthenticationFilterProcessUrl() {
- String url = "/login/cas";
- CasAuthenticationFilter filter = new CasAuthenticationFilter();
- filter.setFilterProcessesUrl(url);
- MockHttpServletRequest request = new MockHttpServletRequest();
- MockHttpServletResponse response = new MockHttpServletResponse();
- request.setServletPath(url);
- assertThat(filter.requiresAuthentication(request, response)).isTrue();
- }
-
- @Test
- public void testRequiresAuthenticationProxyRequest() {
- CasAuthenticationFilter filter = new CasAuthenticationFilter();
- MockHttpServletRequest request = new MockHttpServletRequest();
- MockHttpServletResponse response = new MockHttpServletResponse();
- request.setServletPath("/pgtCallback");
- assertThat(filter.requiresAuthentication(request, response)).isFalse();
- filter.setProxyReceptorUrl(request.getServletPath());
- assertThat(filter.requiresAuthentication(request, response)).isFalse();
- filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
- assertThat(filter.requiresAuthentication(request, response)).isTrue();
- request.setServletPath("/other");
- assertThat(filter.requiresAuthentication(request, response)).isFalse();
- }
-
- @Test
- public void testRequiresAuthenticationAuthAll() {
- ServiceProperties properties = new ServiceProperties();
- properties.setAuthenticateAllArtifacts(true);
- String url = "/login/cas";
- CasAuthenticationFilter filter = new CasAuthenticationFilter();
- filter.setFilterProcessesUrl(url);
- filter.setServiceProperties(properties);
- MockHttpServletRequest request = new MockHttpServletRequest();
- MockHttpServletResponse response = new MockHttpServletResponse();
- request.setServletPath(url);
- assertThat(filter.requiresAuthentication(request, response)).isTrue();
- request.setServletPath("/other");
- assertThat(filter.requiresAuthentication(request, response)).isFalse();
- request.setParameter(properties.getArtifactParameter(), "value");
- assertThat(filter.requiresAuthentication(request, response)).isTrue();
- SecurityContextHolder.getContext().setAuthentication(new AnonymousAuthenticationToken("key", "principal",
- AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")));
- assertThat(filter.requiresAuthentication(request, response)).isTrue();
- SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("un", "principal"));
- assertThat(filter.requiresAuthentication(request, response)).isTrue();
- SecurityContextHolder.getContext()
- .setAuthentication(new TestingAuthenticationToken("un", "principal", "ROLE_ANONYMOUS"));
- assertThat(filter.requiresAuthentication(request, response)).isFalse();
- }
-
- @Test
- public void testAuthenticateProxyUrl() throws Exception {
- CasAuthenticationFilter filter = new CasAuthenticationFilter();
- MockHttpServletRequest request = new MockHttpServletRequest();
- MockHttpServletResponse response = new MockHttpServletResponse();
- request.setServletPath("/pgtCallback");
- filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
- filter.setProxyReceptorUrl(request.getServletPath());
- assertThat(filter.attemptAuthentication(request, response)).isNull();
- }
-
- @Test
- public void testDoFilterAuthenticateAll() throws Exception {
- AuthenticationSuccessHandler successHandler = mock(AuthenticationSuccessHandler.class);
- AuthenticationManager manager = mock(AuthenticationManager.class);
- Authentication authentication = new TestingAuthenticationToken("un", "pwd", "ROLE_USER");
- given(manager.authenticate(any(Authentication.class))).willReturn(authentication);
- ServiceProperties serviceProperties = new ServiceProperties();
- serviceProperties.setAuthenticateAllArtifacts(true);
- MockHttpServletRequest request = new MockHttpServletRequest();
- request.setParameter("ticket", "ST-1-123");
- request.setServletPath("/authenticate");
- MockHttpServletResponse response = new MockHttpServletResponse();
- FilterChain chain = mock(FilterChain.class);
- CasAuthenticationFilter filter = new CasAuthenticationFilter();
- filter.setServiceProperties(serviceProperties);
- filter.setAuthenticationSuccessHandler(successHandler);
- filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
- filter.setAuthenticationManager(manager);
- filter.afterPropertiesSet();
- filter.doFilter(request, response, chain);
- assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull()
- .withFailMessage("Authentication should not be null");
- verify(chain).doFilter(request, response);
- verifyZeroInteractions(successHandler);
- // validate for when the filterProcessUrl matches
- filter.setFilterProcessesUrl(request.getServletPath());
- SecurityContextHolder.clearContext();
- filter.doFilter(request, response, chain);
- verifyNoMoreInteractions(chain);
- verify(successHandler).onAuthenticationSuccess(request, response, authentication);
- }
-
- // SEC-1592
- @Test
- public void testChainNotInvokedForProxyReceptor() throws Exception {
- CasAuthenticationFilter filter = new CasAuthenticationFilter();
- MockHttpServletRequest request = new MockHttpServletRequest();
- MockHttpServletResponse response = new MockHttpServletResponse();
- FilterChain chain = mock(FilterChain.class);
- request.setServletPath("/pgtCallback");
- filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
- filter.setProxyReceptorUrl(request.getServletPath());
- filter.doFilter(request, response, chain);
- verifyZeroInteractions(chain);
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/web/ServicePropertiesTests.java b/cas/src/test/java/org/springframework/security/cas/web/ServicePropertiesTests.java
deleted file mode 100644
index fc52e1d6a54..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/web/ServicePropertiesTests.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.web;
-
-import org.junit.jupiter.api.Test;
-
-import org.springframework.security.cas.SamlServiceProperties;
-import org.springframework.security.cas.ServiceProperties;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-
-/**
- * Tests {@link ServiceProperties}.
- *
- * @author Ben Alex
- */
-public class ServicePropertiesTests {
-
- @Test
- public void detectsMissingService() throws Exception {
- ServiceProperties sp = new ServiceProperties();
- assertThatIllegalArgumentException().isThrownBy(sp::afterPropertiesSet);
- }
-
- @Test
- public void nullServiceWhenAuthenticateAllTokens() throws Exception {
- ServiceProperties sp = new ServiceProperties();
- sp.setAuthenticateAllArtifacts(true);
- assertThatIllegalArgumentException().isThrownBy(sp::afterPropertiesSet);
- sp.setAuthenticateAllArtifacts(false);
- assertThatIllegalArgumentException().isThrownBy(sp::afterPropertiesSet);
- }
-
- @Test
- public void testGettersSetters() throws Exception {
- ServiceProperties[] sps = { new ServiceProperties(), new SamlServiceProperties() };
- for (ServiceProperties sp : sps) {
- sp.setSendRenew(false);
- assertThat(sp.isSendRenew()).isFalse();
- sp.setSendRenew(true);
- assertThat(sp.isSendRenew()).isTrue();
- sp.setArtifactParameter("notticket");
- assertThat(sp.getArtifactParameter()).isEqualTo("notticket");
- sp.setServiceParameter("notservice");
- assertThat(sp.getServiceParameter()).isEqualTo("notservice");
- sp.setService("https://mycompany.com/service");
- assertThat(sp.getService()).isEqualTo("https://mycompany.com/service");
- sp.afterPropertiesSet();
- }
- }
-
-}
diff --git a/cas/src/test/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetailsTests.java b/cas/src/test/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetailsTests.java
deleted file mode 100644
index 893d2567751..00000000000
--- a/cas/src/test/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetailsTests.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2011-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.cas.web.authentication;
-
-import java.util.regex.Pattern;
-
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.support.GenericXmlApplicationContext;
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.security.cas.ServiceProperties;
-import org.springframework.security.web.util.UrlUtils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * @author Rob Winch
- */
-public class DefaultServiceAuthenticationDetailsTests {
-
- private DefaultServiceAuthenticationDetails details;
-
- private MockHttpServletRequest request;
-
- private Pattern artifactPattern;
-
- private String casServiceUrl;
-
- private ConfigurableApplicationContext context;
-
- @BeforeEach
- public void setUp() {
- this.casServiceUrl = "https://localhost:8443/j_spring_security_cas";
- this.request = new MockHttpServletRequest();
- this.request.setScheme("https");
- this.request.setServerName("localhost");
- this.request.setServerPort(8443);
- this.request.setRequestURI("/cas-sample/secure/");
- this.artifactPattern = DefaultServiceAuthenticationDetails
- .createArtifactPattern(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
- }
-
- @AfterEach
- public void cleanup() {
- if (this.context != null) {
- this.context.close();
- }
- }
-
- @Test
- public void getServiceUrlNullQuery() throws Exception {
- this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
- assertThat(this.details.getServiceUrl()).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
- }
-
- @Test
- public void getServiceUrlTicketOnlyParam() throws Exception {
- this.request.setQueryString("ticket=123");
- this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
- String serviceUrl = this.details.getServiceUrl();
- this.request.setQueryString(null);
- assertThat(serviceUrl).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
- }
-
- @Test
- public void getServiceUrlTicketFirstMultiParam() throws Exception {
- this.request.setQueryString("ticket=123&other=value");
- this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
- String serviceUrl = this.details.getServiceUrl();
- this.request.setQueryString("other=value");
- assertThat(serviceUrl).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
- }
-
- @Test
- public void getServiceUrlTicketLastMultiParam() throws Exception {
- this.request.setQueryString("other=value&ticket=123");
- this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
- String serviceUrl = this.details.getServiceUrl();
- this.request.setQueryString("other=value");
- assertThat(serviceUrl).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
- }
-
- @Test
- public void getServiceUrlTicketMiddleMultiParam() throws Exception {
- this.request.setQueryString("other=value&ticket=123&last=this");
- this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
- String serviceUrl = this.details.getServiceUrl();
- this.request.setQueryString("other=value&last=this");
- assertThat(serviceUrl).isEqualTo(UrlUtils.buildFullRequestUrl(this.request));
- }
-
- @Test
- public void getServiceUrlDoesNotUseHostHeader() throws Exception {
- this.casServiceUrl = "https://example.com/j_spring_security_cas";
- this.request.setServerName("evil.com");
- this.details = new DefaultServiceAuthenticationDetails(this.casServiceUrl, this.request, this.artifactPattern);
- assertThat(this.details.getServiceUrl()).isEqualTo("https://example.com/cas-sample/secure/");
- }
-
- @Test
- public void getServiceUrlDoesNotUseHostHeaderExplicit() {
- this.casServiceUrl = "https://example.com/j_spring_security_cas";
- this.request.setServerName("evil.com");
- ServiceAuthenticationDetails details = loadServiceAuthenticationDetails(
- "defaultserviceauthenticationdetails-explicit.xml");
- assertThat(details.getServiceUrl()).isEqualTo("https://example.com/cas-sample/secure/");
- }
-
- private ServiceAuthenticationDetails loadServiceAuthenticationDetails(String resourceName) {
- this.context = new GenericXmlApplicationContext(getClass(), resourceName);
- ServiceAuthenticationDetailsSource source = this.context.getBean(ServiceAuthenticationDetailsSource.class);
- return source.buildDetails(this.request);
- }
-
-}
diff --git a/cas/src/test/resources/logback-test.xml b/cas/src/test/resources/logback-test.xml
deleted file mode 100644
index 2d51ba4180a..00000000000
--- a/cas/src/test/resources/logback-test.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
-
-
-
-
-
-
-
-
-
-
-
diff --git a/cas/src/test/resources/org/springframework/security/cas/web/authentication/defaultserviceauthenticationdetails-explicit.xml b/cas/src/test/resources/org/springframework/security/cas/web/authentication/defaultserviceauthenticationdetails-explicit.xml
deleted file mode 100644
index c7d5346179a..00000000000
--- a/cas/src/test/resources/org/springframework/security/cas/web/authentication/defaultserviceauthenticationdetails-explicit.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cas/src/test/resources/org/springframework/security/cas/web/authentication/defaultserviceauthenticationdetails-passivity.xml b/cas/src/test/resources/org/springframework/security/cas/web/authentication/defaultserviceauthenticationdetails-passivity.xml
deleted file mode 100644
index 0fe950ff2b9..00000000000
--- a/cas/src/test/resources/org/springframework/security/cas/web/authentication/defaultserviceauthenticationdetails-passivity.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/spring-security-config.gradle b/config/spring-security-config.gradle
index a54edbd15c8..fa04b5286dc 100644
--- a/config/spring-security-config.gradle
+++ b/config/spring-security-config.gradle
@@ -37,12 +37,11 @@ dependencies {
optional'org.springframework:spring-websocket'
optional 'org.jetbrains.kotlin:kotlin-reflect'
optional 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
- optional 'javax.annotation:jsr250-api'
+ optional 'jakarta.annotation:jakarta.annotation-api'
- provided 'javax.servlet:javax.servlet-api'
+ provided 'jakarta.servlet:jakarta.servlet-api'
testImplementation project(':spring-security-aspects')
- testImplementation project(':spring-security-cas')
testImplementation project(':spring-security-test')
testImplementation project(path : ':spring-security-core', configuration : 'tests')
testImplementation project(path : ':spring-security-ldap', configuration : 'tests')
@@ -62,8 +61,8 @@ dependencies {
testImplementation 'ch.qos.logback:logback-classic'
testImplementation 'io.projectreactor.netty:reactor-netty'
testImplementation 'io.rsocket:rsocket-transport-netty'
- testImplementation 'javax.annotation:jsr250-api:1.0'
- testImplementation 'javax.xml.bind:jaxb-api'
+ testImplementation 'jakarta.annotation:jakarta.annotation-api'
+ testImplementation 'jakarta.xml.bind:jakarta.xml.bind-api'
testImplementation 'ldapsdk:ldapsdk:4.1'
testImplementation('net.sourceforge.htmlunit:htmlunit') {
exclude group: 'commons-logging', module: 'commons-logging'
@@ -74,8 +73,8 @@ dependencies {
testImplementation "org.apache.directory.server:apacheds-protocol-ldap"
testImplementation "org.apache.directory.server:apacheds-server-jndi"
testImplementation 'org.apache.directory.shared:shared-ldap'
- testImplementation 'org.eclipse.persistence:javax.persistence'
- testImplementation 'org.hibernate:hibernate-entitymanager'
+ testImplementation 'jakarta.persistence:jakarta.persistence-api'
+ testImplementation 'org.hibernate:hibernate-core-jakarta'
testImplementation 'org.hsqldb:hsqldb'
testImplementation 'org.mockito:mockito-core'
testImplementation "org.mockito:mockito-inline"
@@ -117,7 +116,7 @@ tasks.withType(KotlinCompile).configureEach {
languageVersion = "1.3"
apiVersion = "1.3"
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
- jvmTarget = "1.8"
+ jvmTarget = "11"
}
}
diff --git a/config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java b/config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java
index d3dd04a7d9c..9e56d238fe5 100644
--- a/config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java
+++ b/config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java
@@ -94,7 +94,7 @@ public BeanDefinition parse(Element element, ParserContext pc) {
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.6. Please update your schema declarations to the 5.6 schema.", element);
+ + "with Spring Security 6.0. Please update your schema declarations to the 6.0 schema.", element);
}
String name = pc.getDelegate().getLocalName(element);
BeanDefinitionParser parser = this.parsers.get(name);
@@ -215,7 +215,7 @@ private boolean namespaceMatchesVersion(Element element) {
private boolean matchesVersionInternal(Element element) {
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
- return schemaLocation.matches("(?m).*spring-security-5\\.6.*.xsd.*")
+ return schemaLocation.matches("(?m).*spring-security-6\\.0.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
}
diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java
index 07605a3fead..873936a4924 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 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.
@@ -141,7 +141,7 @@ private LdapAuthoritiesPopulator getLdapAuthoritiesPopulator() {
defaultAuthoritiesPopulator.setGroupSearchFilter(this.groupSearchFilter);
defaultAuthoritiesPopulator.setSearchSubtree(this.groupSearchSubtree);
defaultAuthoritiesPopulator.setRolePrefix(this.rolePrefix);
- this.ldapAuthoritiesPopulator = defaultAuthoritiesPopulator;
+ this.ldapAuthoritiesPopulator = postProcess(defaultAuthoritiesPopulator);
return defaultAuthoritiesPopulator;
}
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java b/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java
index d2cea903a43..c99587681bf 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java
@@ -20,7 +20,7 @@
import java.util.Arrays;
import java.util.List;
-import javax.servlet.DispatcherType;
+import jakarta.servlet.DispatcherType;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java b/config/src/main/java/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java
index 475f2de2f50..c3da8890e37 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java
@@ -16,7 +16,7 @@
package org.springframework.security.config.annotation.web;
-import javax.servlet.Filter;
+import jakarta.servlet.Filter;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.SecurityBuilder;
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/WebSecurityConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/WebSecurityConfigurer.java
index c7bc0578d5f..981fdd3742f 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/WebSecurityConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/WebSecurityConfigurer.java
@@ -16,7 +16,7 @@
package org.springframework.security.config.annotation.web;
-import javax.servlet.Filter;
+import jakarta.servlet.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.SecurityBuilder;
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/FilterOrderRegistration.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/FilterOrderRegistration.java
index 13248b7e679..2026e7d8557 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/FilterOrderRegistration.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/FilterOrderRegistration.java
@@ -20,7 +20,7 @@
import java.util.HashMap;
import java.util.Map;
-import javax.servlet.Filter;
+import jakarta.servlet.Filter;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
index 14d32ecd76c..7f04681042d 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
@@ -21,12 +21,12 @@
import java.util.List;
import java.util.Map;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.ApplicationContext;
import org.springframework.core.OrderComparator;
@@ -1048,7 +1048,7 @@ public HttpSecurity x509(Customizer> x509Customizer
* The following configuration demonstrates how to allow token based remember me
* authentication. Upon authenticating if the HTTP parameter named "remember-me"
* exists, then the user will be remembered even after their
- * {@link javax.servlet.http.HttpSession} expires.
+ * {@link jakarta.servlet.http.HttpSession} expires.
*
*
* @Configuration
@@ -1084,7 +1084,7 @@ public RememberMeConfigurer rememberMe() throws Exception {
* The following configuration demonstrates how to allow token based remember me
* authentication. Upon authenticating if the HTTP parameter named "remember-me"
* exists, then the user will be remembered even after their
- * {@link javax.servlet.http.HttpSession} expires.
+ * {@link jakarta.servlet.http.HttpSession} expires.
*
*
* @Configuration
@@ -2889,8 +2889,15 @@ protected void beforeConfigure() throws Exception {
}
}
+ @SuppressWarnings("unchecked")
@Override
protected DefaultSecurityFilterChain performBuild() {
+ ExpressionUrlAuthorizationConfigurer> expressionConfigurer = getConfigurer(
+ ExpressionUrlAuthorizationConfigurer.class);
+ AuthorizeHttpRequestsConfigurer> httpConfigurer = getConfigurer(AuthorizeHttpRequestsConfigurer.class);
+ boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
+ Assert.state((expressionConfigurer == null && httpConfigurer == null) || oneConfigurerPresent,
+ "authorizeHttpRequests cannot be used in conjunction with authorizeRequests. Please select just one.");
this.filters.sort(OrderComparator.INSTANCE);
List sortedFilters = new ArrayList<>(this.filters.size());
for (Filter filter : this.filters) {
@@ -3234,7 +3241,9 @@ public HttpSecurity antMatcher(String antPattern) {
* @see MvcRequestMatcher
*/
public HttpSecurity mvcMatcher(String mvcPattern) {
- HandlerMappingIntrospector introspector = new HandlerMappingIntrospector(getContext());
+ HandlerMappingIntrospector introspector = new HandlerMappingIntrospector();
+ introspector.setApplicationContext(getContext());
+ introspector.afterPropertiesSet();
return requestMatcher(new MvcRequestMatcher(introspector, mvcPattern));
}
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java
index f0395b840ea..8bd1c67d83a 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java
@@ -19,8 +19,9 @@
import java.util.ArrayList;
import java.util.List;
-import javax.servlet.Filter;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.Filter;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -33,6 +34,7 @@
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
+import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityBuilder;
@@ -47,9 +49,12 @@
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
+import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
+import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.debug.DebugFilter;
import org.springframework.security.web.firewall.HttpFirewall;
@@ -57,7 +62,9 @@
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcherEntry;
import org.springframework.util.Assert;
+import org.springframework.web.context.ServletContextAware;
import org.springframework.web.filter.DelegatingFilterProxy;
/**
@@ -81,7 +88,7 @@
* @see WebSecurityConfiguration
*/
public final class WebSecurity extends AbstractConfiguredSecurityBuilder
- implements SecurityBuilder, ApplicationContextAware {
+ implements SecurityBuilder, ApplicationContextAware, ServletContextAware {
private final Log logger = LogFactory.getLog(getClass());
@@ -108,6 +115,8 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder {
};
+ private ServletContext servletContext;
+
/**
* Creates a new instance
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
@@ -252,6 +261,8 @@ public WebInvocationPrivilegeEvaluator getPrivilegeEvaluator() {
* {@link WebSecurityConfigurerAdapter}.
* @param securityInterceptor the {@link FilterSecurityInterceptor} to use
* @return the {@link WebSecurity} for further customizations
+ * @deprecated Use {@link #privilegeEvaluator(WebInvocationPrivilegeEvaluator)}
+ * instead
*/
public WebSecurity securityInterceptor(FilterSecurityInterceptor securityInterceptor) {
this.filterSecurityInterceptor = securityInterceptor;
@@ -278,11 +289,22 @@ protected Filter performBuild() throws Exception {
+ ".addSecurityFilterChainBuilder directly");
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
List securityFilterChains = new ArrayList<>(chainSize);
+ List>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
- securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
+ SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
+ securityFilterChains.add(securityFilterChain);
+ requestMatcherPrivilegeEvaluatorsEntries
+ .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
for (SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
- securityFilterChains.add(securityFilterChainBuilder.build());
+ SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
+ securityFilterChains.add(securityFilterChain);
+ requestMatcherPrivilegeEvaluatorsEntries
+ .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
+ }
+ if (this.privilegeEvaluator == null) {
+ this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
+ requestMatcherPrivilegeEvaluatorsEntries);
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (this.httpFirewall != null) {
@@ -306,6 +328,26 @@ protected Filter performBuild() throws Exception {
return result;
}
+ private RequestMatcherEntry> getRequestMatcherPrivilegeEvaluatorsEntry(
+ SecurityFilterChain securityFilterChain) {
+ List privilegeEvaluators = new ArrayList<>();
+ for (Filter filter : securityFilterChain.getFilters()) {
+ if (filter instanceof FilterSecurityInterceptor) {
+ DefaultWebInvocationPrivilegeEvaluator defaultWebInvocationPrivilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator(
+ (FilterSecurityInterceptor) filter);
+ defaultWebInvocationPrivilegeEvaluator.setServletContext(this.servletContext);
+ privilegeEvaluators.add(defaultWebInvocationPrivilegeEvaluator);
+ continue;
+ }
+ if (filter instanceof AuthorizationFilter) {
+ AuthorizationManager authorizationManager = ((AuthorizationFilter) filter)
+ .getAuthorizationManager();
+ privilegeEvaluators.add(new AuthorizationManagerWebInvocationPrivilegeEvaluator(authorizationManager));
+ }
+ }
+ return new RequestMatcherEntry<>(securityFilterChain::matches, privilegeEvaluators);
+ }
+
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.defaultWebSecurityExpressionHandler.setApplicationContext(applicationContext);
@@ -333,6 +375,11 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
}
}
+ @Override
+ public void setServletContext(ServletContext servletContext) {
+ this.servletContext = servletContext;
+ }
+
/**
* An {@link IgnoredRequestConfigurer} that allows optionally configuring the
* {@link MvcRequestMatcher#setMethod(HttpMethod)}
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/AutowiredWebSecurityConfigurersIgnoreParents.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/AutowiredWebSecurityConfigurersIgnoreParents.java
index dec674d3054..5ac1033e911 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/AutowiredWebSecurityConfigurersIgnoreParents.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/AutowiredWebSecurityConfigurersIgnoreParents.java
@@ -21,7 +21,7 @@
import java.util.Map;
import java.util.Map.Entry;
-import javax.servlet.Filter;
+import jakarta.servlet.Filter;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfiguration.java
index 2783cb358bc..6695e855b73 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfiguration.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 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,13 +16,17 @@
package org.springframework.security.config.annotation.web.configuration;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
+import java.util.function.Supplier;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
@@ -67,17 +71,22 @@ static class SecurityReactorContextSubscriberRegistrar implements InitializingBe
private static final String SECURITY_REACTOR_CONTEXT_OPERATOR_KEY = "org.springframework.security.SECURITY_REACTOR_CONTEXT_OPERATOR";
+ private static final Map