Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 11614edcfe | |||
| 2461d00f4d | |||
| eec6729125 | |||
| fc9c2513d8 | |||
| 1f3c4707f3 | |||
| 579fc565ae | |||
| 5cf23585c0 | |||
| 50d793eab2 | |||
| c715df687a | |||
| 4ddecdbe36 | |||
| 94c8830f76 | |||
| 885f1d3165 | |||
| e414d2bd5c | |||
| dbcc3130ee | |||
| ac9c398fea | |||
| 7c428fb75e | |||
| aa1934ee95 | |||
| 58e8fe837f | |||
| fc25b87967 | |||
| f39f215140 | |||
| 626e53d121 | |||
| a5464ed819 | |||
| 667cab6cda | |||
| 52c7141aac | |||
| e23c1cf7a7 | |||
| 14a48ea939 | |||
| 709de43e89 | |||
| c2e86ad067 | |||
| 9c6d90490d | |||
| 9b3f834bff | |||
| 70bfc39418 | |||
| 621889fa18 | |||
| fe252f5057 | |||
| f561d3784e | |||
| 2d19d972f4 | |||
| d5aabd721a | |||
| 8441e755d3 | |||
| 53148dc7b5 | |||
| 79483b2bc9 | |||
| ed3af6482d | |||
| 67a1f0836b | |||
| fde26e003a | |||
| 40548eb963 | |||
| 8cde8fb363 | |||
| ab5299b6a3 | |||
| 1c9ea52e44 | |||
| 067fc1678c | |||
| 01a37dd678 | |||
| aad01447c3 | |||
| 6efac34ca7 | |||
| 5c4362bbc4 | |||
| c94e33b6c8 | |||
| 8315545144 | |||
| 752e943492 | |||
| e9db852d6e | |||
| 92c1281a56 | |||
| ef41b8c2f2 | |||
| 60f44b347f |
@@ -1,5 +0,0 @@
|
||||
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-reference"}' https://api.github.com/repos/${REPOSITORY_REF}/dispatches
|
||||
echo "Requested Build for $REPOSITORY_REF"
|
||||
@@ -1,41 +0,0 @@
|
||||
name: Generate Antora Files and Request Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'gh-pages'
|
||||
tags: '**'
|
||||
|
||||
env:
|
||||
GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Generate antora.yml
|
||||
run: ./gradlew :spring-security-docs:generateAntora
|
||||
- name: Extract Branch Name
|
||||
id: extract_branch_name
|
||||
run: echo "##[set-output name=generated_branch_name;]$(echo ${GITHUB_REPOSITORY}/${GITHUB_REF##*/})"
|
||||
- name: Push generated antora files to the spring-generated-docs
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.4
|
||||
with:
|
||||
branch: ${{ steps.extract_branch_name.outputs.generated_branch_name }} # The branch the action should deploy to.
|
||||
folder: "docs/build/generateAntora" # The folder the action should deploy.
|
||||
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-projects/spring-security' "$GH_ACTIONS_REPO_TOKEN"
|
||||
@@ -31,15 +31,15 @@ jobs:
|
||||
runjobs: ${{ steps.continue.outputs.runjobs }}
|
||||
project_version: ${{ steps.continue.outputs.project_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- id: continue
|
||||
name: Determine if should continue
|
||||
run: |
|
||||
# Run jobs if in upstream repository
|
||||
echo "::set-output name=runjobs::true"
|
||||
echo "runjobs=true" >>$GITHUB_OUTPUT
|
||||
# Extract version from gradle.properties
|
||||
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
|
||||
echo "::set-output name=project_version::$version"
|
||||
echo "project_version=$version" >>$GITHUB_OUTPUT
|
||||
build_jdk_11:
|
||||
name: Build JDK 11
|
||||
needs: [prerequisites]
|
||||
@@ -49,9 +49,9 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
if: needs.prerequisites.outputs.runjobs
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.prerequisites.outputs.runjobs
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.prerequisites.outputs.runjobs
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
@@ -113,7 +113,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.prerequisites.outputs.runjobs
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
@@ -130,7 +130,7 @@ jobs:
|
||||
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
@@ -154,7 +154,7 @@ jobs:
|
||||
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
@@ -175,7 +175,7 @@ jobs:
|
||||
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
@@ -205,7 +205,7 @@ jobs:
|
||||
TOKEN: ${{ github.token }}
|
||||
VERSION: ${{ needs.prerequisites.outputs.project_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
- name: Set up gradle
|
||||
@@ -286,7 +286,7 @@ jobs:
|
||||
TOKEN: ${{ github.token }}
|
||||
VERSION: ${{ needs.prerequisites.outputs.project_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
name: Deploy Docs
|
||||
on:
|
||||
push:
|
||||
branches-ignore: [ gh-pages ]
|
||||
tags: '**'
|
||||
repository_dispatch:
|
||||
types: request-build-reference # legacy
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
workflow_dispatch:
|
||||
permissions: read-all
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'spring-projects'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: docs-build
|
||||
fetch-depth: 1
|
||||
- name: Dispatch (partial build)
|
||||
if: github.ref_type == 'branch'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
|
||||
- name: Dispatch (full build)
|
||||
if: github.ref_type == 'tag'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD)
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
steps:
|
||||
- id: checkout-source
|
||||
name: Checkout Source Code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
- name: Set up gradle
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
|
||||
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
|
||||
./gradlew gitHubCheckNextVersionDueToday
|
||||
echo "::set-output name=is_due_today::$(cat build/github/milestones/is-due-today)"
|
||||
echo "is_due_today=$(cat build/github/milestones/is-due-today)" >>$GITHUB_OUTPUT
|
||||
- id: check-open-issues
|
||||
name: Check for open issues
|
||||
if: steps.check-release-due.outputs.is_due_today == 'true'
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
|
||||
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
|
||||
./gradlew gitHubCheckMilestoneHasNoOpenIssues
|
||||
echo "::set-output name=is_open_issues::$(cat build/github/milestones/is-open-issues)"
|
||||
echo "is_open_issues=$(cat build/github/milestones/is-open-issues)" >>$GITHUB_OUTPUT
|
||||
- id: validate-release-state
|
||||
name: Validate State of Release
|
||||
if: steps.check-release-due.outputs.is_due_today == 'true' && steps.check-open-issues.outputs.is_open_issues == 'true'
|
||||
|
||||
@@ -196,7 +196,6 @@ if (hasProperty('buildScan')) {
|
||||
}
|
||||
|
||||
nohttp {
|
||||
allowlistFile = project.file("etc/nohttp/allowlist.lines")
|
||||
source.exclude "buildSrc/build/**"
|
||||
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ dependencies {
|
||||
|
||||
implementation 'io.github.gradle-nexus:publish-plugin:1.1.0'
|
||||
implementation 'io.projectreactor:reactor-core:3.5.0-M1'
|
||||
implementation 'gradle.plugin.org.gretty:gretty:3.0.1'
|
||||
implementation 'org.gretty:gretty:3.0.9'
|
||||
implementation 'com.apollographql.apollo:apollo-runtime:2.4.5'
|
||||
implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
|
||||
implementation 'com.github.spullara.mustache.java:compiler:0.9.4'
|
||||
|
||||
BIN
Binary file not shown.
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original 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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -102,6 +102,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
if (parser == null) {
|
||||
// SEC-1455. Load parsers when required, not just on init().
|
||||
loadParsers();
|
||||
parser = this.parsers.get(name);
|
||||
}
|
||||
if (parser != null) {
|
||||
return parser.parse(element, pc);
|
||||
|
||||
+18
-1
@@ -91,7 +91,24 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
* @see EnableWebSecurity
|
||||
* @deprecated Use a {@link org.springframework.security.web.SecurityFilterChain} Bean to
|
||||
* configure {@link HttpSecurity} or a {@link WebSecurityCustomizer} Bean to configure
|
||||
* {@link WebSecurity}
|
||||
* {@link WebSecurity}. <pre>
|
||||
* @Bean
|
||||
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
* http
|
||||
* .authorizeHttpRequests((authz) ->
|
||||
* authz.anyRequest().authenticated()
|
||||
* );
|
||||
* // ...
|
||||
* return http.build();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public WebSecurityCustomizer webSecurityCustomizer(WebSecurity web) {
|
||||
* return (web) -> web.ignoring().antMatchers("/resources/**");
|
||||
* }
|
||||
* </pre> See the <a href=
|
||||
* "https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter">Spring
|
||||
* Security without WebSecurityConfigurerAdapter</a> for more details.
|
||||
*/
|
||||
@Order(100)
|
||||
@Deprecated
|
||||
|
||||
+2
-1
@@ -50,7 +50,8 @@ import org.springframework.security.web.csrf.CsrfToken;
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* No shared objects are created. isLogoutRequest
|
||||
* No shared objects are created.
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* The following shared objects are used:
|
||||
|
||||
+5
-4
@@ -49,10 +49,11 @@ import org.springframework.util.Assert;
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* protected void configure(HttpSecurity http) throws Exception {
|
||||
* http.apply(new UrlAuthorizationConfigurer<HttpSecurity>()).getRegistry()
|
||||
* .antMatchers("/users**", "/sessions/**").hasRole("USER")
|
||||
* .antMatchers("/signup").hasRole("ANONYMOUS").anyRequest().hasRole("USER");
|
||||
* @Bean
|
||||
* public SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context) throws Exception {
|
||||
* http.apply(new UrlAuthorizationConfigurer<HttpSecurity>(context)).getRegistry()
|
||||
* .requestMatchers("/users**", "/sessions/**").hasRole("USER")
|
||||
* .requestMatchers("/signup").hasRole("ANONYMOUS").anyRequest().hasRole("USER");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
|
||||
+3
-2
@@ -40,8 +40,9 @@ import org.springframework.util.Assert;
|
||||
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
|
||||
|
||||
/**
|
||||
* The plaintext password used to perform PasswordEncoder#matches(CharSequence,
|
||||
* String)} on when the user is not found to avoid SEC-2056.
|
||||
* The plaintext password used to perform
|
||||
* {@link PasswordEncoder#matches(CharSequence, String)} on when the user is not found
|
||||
* to avoid SEC-2056.
|
||||
*/
|
||||
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
|
||||
|
||||
|
||||
+7
-7
@@ -8,13 +8,13 @@ javaPlatform {
|
||||
|
||||
dependencies {
|
||||
api platform("org.springframework:spring-framework-bom:$springFrameworkVersion")
|
||||
api platform("io.projectreactor:reactor-bom:2020.0.24")
|
||||
api platform("io.projectreactor:reactor-bom:2020.0.26")
|
||||
api platform("io.rsocket:rsocket-bom:1.1.3")
|
||||
api platform("org.junit:junit-bom:5.8.2")
|
||||
api platform("org.springframework.data:spring-data-bom:2021.2.4")
|
||||
api platform("org.springframework.data:spring-data-bom:2021.2.6")
|
||||
api platform("org.jetbrains.kotlin:kotlin-bom:$kotlinVersion")
|
||||
api platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4")
|
||||
api platform("com.fasterxml.jackson:jackson-bom:2.13.4.20221012")
|
||||
api platform("com.fasterxml.jackson:jackson-bom:2.13.4.20221013")
|
||||
constraints {
|
||||
api "ch.qos.logback:logback-classic:1.2.11"
|
||||
api "com.google.inject:guice:3.0"
|
||||
@@ -44,17 +44,17 @@ dependencies {
|
||||
api "org.apache.directory.server:apacheds-protocol-shared:1.5.5"
|
||||
api "org.apache.directory.server:apacheds-server-jndi:1.5.5"
|
||||
api "org.apache.directory.shared:shared-ldap:0.9.15"
|
||||
api "org.apache.httpcomponents:httpclient:4.5.13"
|
||||
api "org.apache.httpcomponents:httpclient:4.5.14"
|
||||
api "org.aspectj:aspectjrt:$aspectjVersion"
|
||||
api "org.aspectj:aspectjweaver:$aspectjVersion"
|
||||
api "org.assertj:assertj-core:3.22.0"
|
||||
api "org.bouncycastle:bcpkix-jdk15on:1.70"
|
||||
api "org.bouncycastle:bcprov-jdk15on:1.70"
|
||||
api "org.eclipse.jetty:jetty-server:9.4.49.v20220914"
|
||||
api "org.eclipse.jetty:jetty-servlet:9.4.49.v20220914"
|
||||
api "org.eclipse.jetty:jetty-server:9.4.50.v20221201"
|
||||
api "org.eclipse.jetty:jetty-servlet:9.4.50.v20221201"
|
||||
api "org.eclipse.persistence:javax.persistence:2.2.1"
|
||||
api "org.hamcrest:hamcrest:2.2"
|
||||
api "org.hibernate:hibernate-entitymanager:5.6.12.Final"
|
||||
api "org.hibernate:hibernate-entitymanager:5.6.14.Final"
|
||||
api "org.hsqldb:hsqldb:2.6.1"
|
||||
api "org.jasig.cas.client:cas-client-core:3.6.4"
|
||||
api "org.mockito:mockito-core:3.12.4"
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
/* Copyright (c) 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const { promises: fsp } = require('fs')
|
||||
const ospath = require('path')
|
||||
|
||||
/**
|
||||
* Rewrites local content sources to support the use of linked worktrees.
|
||||
*
|
||||
* @author Dan Allen <dan@opendevise.com>
|
||||
*/
|
||||
module.exports.register = function () {
|
||||
this.once('playbookBuilt', async ({ playbook }) => {
|
||||
const expandPath = this.require('@antora/expand-path-helper')
|
||||
for (const contentSource of playbook.content.sources) {
|
||||
const { url, branches } = contentSource
|
||||
if (url.charAt() !== '.') continue
|
||||
const absdir = expandPath(url, { dot: playbook.dir })
|
||||
const gitfile = ospath.join(absdir, '.git')
|
||||
if (await fsp.stat(gitfile).then((stat) => !stat.isDirectory(), () => false)) {
|
||||
const worktreeGitdir = await fsp.readFile(gitfile, 'utf8')
|
||||
.then((contents) => contents.trimRight().substr(8))
|
||||
const worktreeBranch = await fsp.readFile(ospath.join(worktreeGitdir, 'HEAD'), 'utf8')
|
||||
.then((contents) => contents.trimRight().replace(/^ref: (?:refs\/heads\/)?/, ''))
|
||||
const reldir = ospath.relative(
|
||||
playbook.dir,
|
||||
await fsp.readFile(ospath.join(worktreeGitdir, 'commondir'), 'utf8')
|
||||
.then((contents) => {
|
||||
const gitdir = ospath.join(worktreeGitdir, contents.trimRight())
|
||||
return ospath.basename(gitdir) === '.git' ? ospath.dirname(gitdir) : gitdir
|
||||
})
|
||||
)
|
||||
contentSource.url = reldir ? `.${ospath.sep}${reldir}` : '.'
|
||||
if (!branches) continue
|
||||
contentSource.branches = (branches.constructor === Array ? branches : [branches])
|
||||
.map((pattern) => pattern.replaceAll('HEAD', worktreeBranch))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
# The purpose of this Antora playbook is to generate a preview of the docs in the current branch.
|
||||
antora:
|
||||
extensions:
|
||||
- ./antora-linked-worktree-patch.js
|
||||
- '@antora/collector-extension'
|
||||
site:
|
||||
title: Spring Security
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 143 KiB |
@@ -645,7 +645,7 @@ If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authe
|
||||
== OpenID Connect 1.0 Logout
|
||||
|
||||
OpenID Connect Session Management 1.0 allows the ability to log out the End-User at the Provider using the Client.
|
||||
One of the strategies available is https://openid.net/specs/openid-connect-session-1_0.html#RPLogout[RP-Initiated Logout].
|
||||
One of the strategies available is https://openid.net/specs/openid-connect-rpinitiated-1_0.html[RP-Initiated Logout].
|
||||
|
||||
If the OpenID Provider supports both Session Management and https://openid.net/specs/openid-connect-discovery-1_0.html[Discovery], the client may obtain the `end_session_endpoint` `URL` from the OpenID Provider's https://openid.net/specs/openid-connect-session-1_0.html#OPMetadata[Discovery Metadata].
|
||||
This can be achieved by configuring the `ClientRegistration` with the `issuer-uri`, as in the following example:
|
||||
|
||||
@@ -47,7 +47,7 @@ UserDetailsService userDetailsService;
|
||||
|
||||
DigestAuthenticationEntryPoint entryPoint() {
|
||||
DigestAuthenticationEntryPoint result = new DigestAuthenticationEntryPoint();
|
||||
result.setRealmName("My App Relam");
|
||||
result.setRealmName("My App Realm");
|
||||
result.setKey("3028472b-da34-4501-bfd8-a355c42bdf92");
|
||||
}
|
||||
|
||||
|
||||
@@ -48,12 +48,10 @@ image::{figures}/authorizationfilter.png[]
|
||||
|
||||
* image:{icondir}/number_1.png[] First, the `AuthorizationFilter` obtains an xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[Authentication] from the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
|
||||
It wraps this in an `Supplier` in order to delay lookup.
|
||||
* image:{icondir}/number_2.png[] Second, `AuthorizationFilter` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain`.
|
||||
// FIXME: link to FilterInvocation
|
||||
* image:{icondir}/number_3.png[] Next, it passes the `Supplier<Authentication>` and `FilterInvocation` to the xref:servlet/architecture.adoc#authz-authorization-manager[`AuthorizationManager`].
|
||||
** image:{icondir}/number_4.png[] If authorization is denied, an `AccessDeniedException` is thrown.
|
||||
* image:{icondir}/number_2.png[] Second, it passes the `Supplier<Authentication>` and the `HttpServletRequest` to the xref:servlet/architecture.adoc#authz-authorization-manager[`AuthorizationManager`].
|
||||
** image:{icondir}/number_3.png[] If authorization is denied, an `AccessDeniedException` is thrown.
|
||||
In this case the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] handles the `AccessDeniedException`.
|
||||
** image:{icondir}/number_5.png[] If access is granted, `AuthorizationFilter` continues with the xref:servlet/architecture.adoc#servlet-filters-review[FilterChain] which allows the application to process normally.
|
||||
** image:{icondir}/number_4.png[] If access is granted, `AuthorizationFilter` continues with the xref:servlet/architecture.adoc#servlet-filters-review[FilterChain] which allows the application to process normally.
|
||||
|
||||
We can configure Spring Security to have different rules by adding more rules in order of precedence.
|
||||
|
||||
|
||||
@@ -865,7 +865,7 @@ If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authe
|
||||
== OpenID Connect 1.0 Logout
|
||||
|
||||
OpenID Connect Session Management 1.0 allows the ability to log out the End-User at the Provider using the Client.
|
||||
One of the strategies available is https://openid.net/specs/openid-connect-session-1_0.html#RPLogout[RP-Initiated Logout].
|
||||
One of the strategies available is https://openid.net/specs/openid-connect-rpinitiated-1_0.html[RP-Initiated Logout].
|
||||
|
||||
If the OpenID Provider supports both Session Management and https://openid.net/specs/openid-connect-discovery-1_0.html[Discovery], the client may obtain the `end_session_endpoint` `URL` from the OpenID Provider's https://openid.net/specs/openid-connect-session-1_0.html#OPMetadata[Discovery Metadata].
|
||||
This can be achieved by configuring the `ClientRegistration` with the `issuer-uri`, as in the following example:
|
||||
|
||||
@@ -248,7 +248,7 @@ public class TenantJWSKeySelector
|
||||
}
|
||||
|
||||
private JWSKeySelector<SecurityContext> fromTenant(String tenant) {
|
||||
return Optional.ofNullable(this.tenantRepository.findById(tenant)) <3>
|
||||
return Optional.ofNullable(this.tenants.findById(tenant)) <3>
|
||||
.map(t -> t.getAttrbute("jwks_uri"))
|
||||
.map(this::fromUri)
|
||||
.orElseThrow(() -> new IllegalArgumentException("unknown tenant"));
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
As described in xref:servlet/oauth2/resource-server/jwt.adoc#oauth2resourceserver-jwt-minimaldependencies[Minimal Dependencies for JWT] most of Resource Server support is collected in `spring-security-oauth2-resource-server`.
|
||||
However unless a custom <<oauth2resourceserver-opaque-introspector,`OpaqueTokenIntrospector`>> is provided, the Resource Server will fallback to NimbusOpaqueTokenIntrospector.
|
||||
Meaning that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens.
|
||||
Please refer to `spring-security-oauth2-resource-server` in order to determin the correct version for `oauth2-oidc-sdk`.
|
||||
Please refer to `spring-security-oauth2-resource-server` in order to determine the correct version for `oauth2-oidc-sdk`.
|
||||
|
||||
[[oauth2resourceserver-opaque-minimalconfiguration]]
|
||||
== Minimal Configuration for Introspection
|
||||
|
||||
@@ -6,7 +6,7 @@ apply plugin: 'io.spring.convention.docs'
|
||||
apply plugin: 'java'
|
||||
|
||||
antora {
|
||||
version = '~3.1'
|
||||
version = '3.2.0-alpha.2'
|
||||
playbook = file('local-antora-playbook.yml')
|
||||
options = ['--clean', '--stacktrace']
|
||||
environment = [
|
||||
@@ -15,7 +15,7 @@ antora {
|
||||
'ALGOLIA_INDEX_NAME': 'security-docs'
|
||||
]
|
||||
dependencies = [
|
||||
'@antora/collector-extension': '1.0.0-alpha.2'
|
||||
'@antora/collector-extension': '1.0.0-alpha.3'
|
||||
]
|
||||
}
|
||||
|
||||
@@ -38,14 +38,22 @@ tasks.register('generateAntora') {
|
||||
.join('\n')
|
||||
def outputFile = layout.buildDirectory.file('generateAntora/antora.yml').get().asFile
|
||||
mkdir(outputFile.getParentFile())
|
||||
def components = project.version.split(/(?=-)/)
|
||||
def mainVersion = components[0];
|
||||
def prerelease = components.length > 1 ? components[1] : null
|
||||
def mainVersion = project.version
|
||||
def prerelease = null
|
||||
def versionComponents = mainVersion.split(/(?=-)/)
|
||||
if (versionComponents.length > 1) {
|
||||
if (versionComponents[1] == '-SNAPSHOT') {
|
||||
mainVersion = versionComponents[0]
|
||||
prerelease = "'-SNAPSHOT'"
|
||||
} else {
|
||||
prerelease = 'true'
|
||||
}
|
||||
}
|
||||
def antoraYmlText = file('antora.yml').text
|
||||
layout.buildDirectory.file('.antora.yml').get().asFile.text = antoraYmlText
|
||||
antoraYmlText = antoraYmlText.lines().collect { l ->
|
||||
if (l.startsWith('version: ')) {
|
||||
return prerelease == null ? "version: '${mainVersion}'" : "version: '${mainVersion}'\nprerelease: '${prerelease}'"
|
||||
return prerelease == null ? "version: '${mainVersion}'" : "version: '${mainVersion}'\nprerelease: ${prerelease}"
|
||||
}
|
||||
if (l.startsWith('title: ')) return "title: ${project.parent.description}"
|
||||
return l == 'ext:' || l.getAt(0) == ' ' ? null : l
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"https://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
<module name="Checker">
|
||||
<property name="charset" value="UTF-8"/>
|
||||
<property name="fileExtensions" value=""/>
|
||||
<module name="io.spring.nohttp.checkstyle.check.NoHttpCheck">
|
||||
<!-- Workaround for https://github.com/spring-io/nohttp/issues/55 -->
|
||||
<property name="allowlistFileName" value="${config_loc}/allowlist.lines" default=""/>
|
||||
</module>
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${config_loc}/suppressions.xml" default=""/>
|
||||
<property name="optional" value="true"/>
|
||||
</module>
|
||||
<module name="SuppressWithPlainTextCommentFilter"/>
|
||||
</module>
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
aspectjVersion=1.9.9.1
|
||||
springJavaformatVersion=0.0.31
|
||||
springBootVersion=2.4.2
|
||||
springFrameworkVersion=5.3.23
|
||||
springFrameworkVersion=5.3.24
|
||||
openSamlVersion=3.4.6
|
||||
version=5.7.5
|
||||
version=5.7.6
|
||||
kotlinVersion=1.6.21
|
||||
samplesBranch=5.7.x
|
||||
org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.ldap.userdetails;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Dayan Kodippily
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(
|
||||
classes = DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.ApacheDsContainerWithUndefinedGroupRoleAttributeConfig.class)
|
||||
public class DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests {
|
||||
|
||||
@Autowired
|
||||
private DefaultSpringSecurityContextSource contextSource;
|
||||
|
||||
private DefaultLdapAuthoritiesPopulator populator;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
this.populator = new DefaultLdapAuthoritiesPopulator(this.contextSource, "ou=groups");
|
||||
this.populator.setIgnorePartialResultException(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupSearchDoesNotAllowNullRoles() {
|
||||
this.populator.setRolePrefix("ROLE_");
|
||||
this.populator.setGroupRoleAttribute("ou");
|
||||
this.populator.setSearchSubtree(true);
|
||||
this.populator.setSearchSubtree(false);
|
||||
this.populator.setConvertToUpperCase(true);
|
||||
this.populator.setGroupSearchFilter("(member={0})");
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(
|
||||
new DistinguishedName("uid=dayan,ou=people,dc=springframework,dc=org"));
|
||||
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(this.populator.getGrantedAuthorities(ctx, "dayan"));
|
||||
|
||||
assertThat(authorities).as("Should have 1 role").hasSize(2);
|
||||
|
||||
assertThat(authorities.contains("ROLE_DEVELOPER")).isTrue();
|
||||
assertThat(authorities.contains("ROLE_")).isTrue();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ApacheDsContainerWithUndefinedGroupRoleAttributeConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapContainer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=springframework,dc=org",
|
||||
"classpath:test-server-with-undefined-group-role-attributes.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ContextSource contextSource(ApacheDSContainer ldapContainer) {
|
||||
return new DefaultSpringSecurityContextSource(
|
||||
"ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
this.container.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
dn: ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: groups
|
||||
|
||||
dn: ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: people
|
||||
|
||||
dn: uid=dayan,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Dayan K
|
||||
sn: Dayan
|
||||
uid: dayan
|
||||
userPassword: dayanspassword
|
||||
|
||||
|
||||
|
||||
dn: cn=managers,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: managers
|
||||
ou:
|
||||
member: uid=dayan,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=researchers,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: researchers
|
||||
member: uid=dayan,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=developers,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: developers
|
||||
ou: developer
|
||||
member: uid=dayan,ou=people,dc=springframework,dc=org
|
||||
+13
-2
@@ -37,6 +37,7 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* The default strategy for obtaining user role information from the directory.
|
||||
@@ -169,7 +170,14 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
logger.info("Will perform group search from the context source base since groupSearchBase is empty.");
|
||||
}
|
||||
this.authorityMapper = (record) -> {
|
||||
String role = record.get(this.groupRoleAttribute).get(0);
|
||||
List<String> roles = record.get(this.groupRoleAttribute);
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return null;
|
||||
}
|
||||
String role = roles.get(0);
|
||||
if (role == null) {
|
||||
return null;
|
||||
}
|
||||
if (this.convertToUpperCase) {
|
||||
role = role.toUpperCase();
|
||||
}
|
||||
@@ -225,7 +233,10 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
new String[] { this.groupRoleAttribute });
|
||||
logger.debug(LogMessage.of(() -> "Found roles from search " + userRoles));
|
||||
for (Map<String, List<String>> role : userRoles) {
|
||||
authorities.add(this.authorityMapper.apply(role));
|
||||
GrantedAuthority authority = this.authorityMapper.apply(role);
|
||||
if (authority != null) {
|
||||
authorities.add(authority);
|
||||
}
|
||||
}
|
||||
return authorities;
|
||||
}
|
||||
|
||||
+6
@@ -173,8 +173,14 @@ public class OidcUserService implements OAuth2UserService<OidcUserRequest, OidcU
|
||||
.equals(userRequest.getClientRegistration().getAuthorizationGrantType())) {
|
||||
// Return true if there is at least one match between the authorized scope(s)
|
||||
// and accessible scope(s)
|
||||
//
|
||||
// Also return true if authorized scope(s) is empty, because the provider has
|
||||
// not indicated which scopes are accessible via the access token
|
||||
// @formatter:off
|
||||
return this.accessibleScopes.isEmpty()
|
||||
|| CollectionUtils.isEmpty(userRequest.getAccessToken().getScopes())
|
||||
|| CollectionUtils.containsAny(userRequest.getAccessToken().getScopes(), this.accessibleScopes);
|
||||
// @formatter:on
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
+1
-2
@@ -42,8 +42,7 @@ import org.springframework.web.util.UriComponentsBuilder;
|
||||
* @author Josh Cummings
|
||||
* @since 5.2
|
||||
* @see <a href=
|
||||
* "https://openid.net/specs/openid-connect-session-1_0.html#RPLogout">RP-Initiated
|
||||
* Logout</a>
|
||||
* "https://openid.net/specs/openid-connect-rpinitiated-1_0.html">RP-Initiated Logout</a>
|
||||
* @see org.springframework.security.web.authentication.logout.LogoutSuccessHandler
|
||||
*/
|
||||
public final class OidcClientInitiatedLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
|
||||
+1
-2
@@ -43,8 +43,7 @@ import org.springframework.web.util.UriComponentsBuilder;
|
||||
* @author Josh Cummings
|
||||
* @since 5.2
|
||||
* @see <a href=
|
||||
* "https://openid.net/specs/openid-connect-session-1_0.html#RPLogout">RP-Initiated
|
||||
* Logout</a>
|
||||
* "https://openid.net/specs/openid-connect-rpinitiated-1_0.html">RP-Initiated Logout</a>
|
||||
* @see org.springframework.security.web.server.authentication.logout.ServerLogoutSuccessHandler
|
||||
*/
|
||||
public class OidcClientInitiatedServerLogoutSuccessHandler implements ServerLogoutSuccessHandler {
|
||||
|
||||
+1
-1
@@ -192,8 +192,8 @@ public class OAuth2AuthorizationRequestRedirectFilter extends OncePerRequestFilt
|
||||
if (authorizationRequest == null) {
|
||||
throw authzEx;
|
||||
}
|
||||
this.sendRedirectForAuthorization(request, response, authorizationRequest);
|
||||
this.requestCache.saveRequest(request, response);
|
||||
this.sendRedirectForAuthorization(request, response, authorizationRequest);
|
||||
}
|
||||
catch (Exception failed) {
|
||||
this.unsuccessfulRedirectForAuthorization(request, response, failed);
|
||||
|
||||
+24
-2
@@ -458,14 +458,36 @@ public class OidcUserServiceTests {
|
||||
@Test
|
||||
public void loadUserWhenTokenDoesNotContainScopesThenNoScopeAuthorities() {
|
||||
OidcUserService userService = new OidcUserService();
|
||||
OidcUserRequest request = new OidcUserRequest(TestClientRegistrations.clientRegistration().build(),
|
||||
TestOAuth2AccessTokens.noScopes(), TestOidcIdTokens.idToken().build());
|
||||
OidcUserRequest request = new OidcUserRequest(this.clientRegistrationBuilder.build(),
|
||||
TestOAuth2AccessTokens.noScopes(), this.idToken);
|
||||
OidcUser user = userService.loadUser(request);
|
||||
assertThat(user.getAuthorities()).hasSize(1);
|
||||
Iterator<? extends GrantedAuthority> authorities = user.getAuthorities().iterator();
|
||||
assertThat(authorities.next()).isInstanceOf(OidcUserAuthority.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadUserWhenTokenDoesNotContainScopesAndUserInfoUriThenUserInfoRequested() {
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
OidcUserService userService = new OidcUserService();
|
||||
OidcUserRequest request = new OidcUserRequest(clientRegistration, TestOAuth2AccessTokens.noScopes(),
|
||||
this.idToken);
|
||||
OidcUser user = userService.loadUser(request);
|
||||
assertThat(user.getUserInfo()).isNotNull();
|
||||
}
|
||||
|
||||
private MockResponse jsonResponse(String json) {
|
||||
// @formatter:off
|
||||
return new MockResponse()
|
||||
|
||||
+19
@@ -48,6 +48,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.willAnswer;
|
||||
import static org.mockito.BDDMockito.willThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -333,4 +334,22 @@ public class OAuth2AuthorizationRequestRedirectFilterTests {
|
||||
+ "login_hint=user@provider\\.com");
|
||||
}
|
||||
|
||||
// gh-11602
|
||||
|
||||
@Test
|
||||
public void doFilterWhenNotAuthorizationRequestAndClientAuthorizationRequiredExceptionThrownThenSaveRequestBeforeCommitted()
|
||||
throws Exception {
|
||||
String requestUri = "/path";
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
|
||||
request.setServletPath(requestUri);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
willAnswer((invocation) -> assertThat((invocation.<HttpServletResponse>getArgument(1)).isCommitted()).isFalse())
|
||||
.given(this.requestCache).saveRequest(any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
willThrow(new ClientAuthorizationRequiredException(this.registration1.getRegistrationId())).given(filterChain)
|
||||
.doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
assertThat(response.isCommitted()).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-1
@@ -16,10 +16,12 @@
|
||||
|
||||
package org.springframework.security.oauth2.core.endpoint;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
|
||||
|
||||
/**
|
||||
@@ -42,7 +44,8 @@ public final class TestOAuth2AccessTokenResponses {
|
||||
public static OAuth2AccessTokenResponse.Builder oidcAccessTokenResponse() {
|
||||
Map<String, Object> additionalParameters = new HashMap<>();
|
||||
additionalParameters.put(OidcParameterNames.ID_TOKEN, "id-token");
|
||||
return accessTokenResponse().additionalParameters(additionalParameters);
|
||||
return accessTokenResponse().scopes(Collections.singleton(OidcScopes.OPENID))
|
||||
.additionalParameters(additionalParameters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -128,7 +128,7 @@ public final class OpenSamlLogoutRequestValidator implements Saml2LogoutRequestV
|
||||
RelyingPartyRegistration registration) {
|
||||
return (errors) -> {
|
||||
if (request.getIssuer() == null) {
|
||||
errors.add(new Saml2Error(Saml2ErrorCodes.INVALID_ISSUER, "Failed to find issuer in LogoutResponse"));
|
||||
errors.add(new Saml2Error(Saml2ErrorCodes.INVALID_ISSUER, "Failed to find issuer in LogoutRequest"));
|
||||
return;
|
||||
}
|
||||
String issuer = request.getIssuer().getValue();
|
||||
@@ -144,7 +144,7 @@ public final class OpenSamlLogoutRequestValidator implements Saml2LogoutRequestV
|
||||
return (errors) -> {
|
||||
if (request.getDestination() == null) {
|
||||
errors.add(new Saml2Error(Saml2ErrorCodes.INVALID_DESTINATION,
|
||||
"Failed to find destination in LogoutResponse"));
|
||||
"Failed to find destination in LogoutRequest"));
|
||||
return;
|
||||
}
|
||||
String destination = request.getDestination();
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -105,6 +105,7 @@ public final class Saml2MetadataFilter extends OncePerRequestFilter {
|
||||
String format = "attachment; filename=\"%s\"; filename*=UTF-8''%s";
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, String.format(format, fileName, encodedFileName));
|
||||
response.setContentLength(metadata.length());
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
response.getWriter().write(metadata);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ public final class Saml2LogoutResponseFilter extends OncePerRequestFilter {
|
||||
logoutRequest.getRelyingPartyRegistrationId());
|
||||
if (registration == null) {
|
||||
this.logger
|
||||
.trace("Did not process logout request since failed to find associated RelyingPartyRegistration");
|
||||
.trace("Did not process logout response since failed to find associated RelyingPartyRegistration");
|
||||
Saml2Error error = new Saml2Error(Saml2ErrorCodes.RELYING_PARTY_REGISTRATION_NOT_FOUND,
|
||||
"Failed to find associated RelyingPartyRegistration");
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, error.toString());
|
||||
|
||||
+16
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -153,6 +153,21 @@ public class Saml2MetadataFilterTests {
|
||||
verify(this.repository).findByRegistrationId("registration-id");
|
||||
}
|
||||
|
||||
// gh-12026
|
||||
@Test
|
||||
public void doFilterWhenCharacterEncodingThenEncodeSpecialCharactersCorrectly() throws Exception {
|
||||
RelyingPartyRegistration validRegistration = TestRelyingPartyRegistrations.full().build();
|
||||
String testMetadataFilename = "test-{registrationId}-metadata.xml";
|
||||
String generatedMetadata = "<xml>testäöü</xml>";
|
||||
this.request.setPathInfo("/saml2/service-provider-metadata/registration-id");
|
||||
given(this.resolver.resolve(validRegistration)).willReturn(generatedMetadata);
|
||||
this.filter = new Saml2MetadataFilter((req, id) -> validRegistration, this.resolver);
|
||||
this.filter.setMetadataFilename(testMetadataFilename);
|
||||
this.filter.doFilter(this.request, this.response, this.chain);
|
||||
assertThat(this.response.getCharacterEncoding()).isEqualTo(StandardCharsets.UTF_8.name());
|
||||
assertThat(this.response.getContentAsString(StandardCharsets.UTF_8)).isEqualTo(generatedMetadata);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRequestMatcherWhenNullThenIllegalArgument() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setRequestMatcher(null));
|
||||
|
||||
Reference in New Issue
Block a user