Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2d2914a4f | |||
| a40f73521c | |||
| 70863952ae | |||
| af95be34c6 | |||
| 71478c2534 | |||
| b289d12aad | |||
| e2361c5c79 | |||
| 8b9c8ca96c | |||
| 44e672d969 | |||
| 330f0f050d | |||
| e45dcb3ab2 | |||
| d3a451fffb | |||
| 9d378103b0 | |||
| 2031f101dc | |||
| 2a2c2dd209 | |||
| fa0e06ebdc | |||
| 6724627b50 | |||
| 4aab7b06a9 | |||
| d0d4d58c48 | |||
| 29be60d035 | |||
| 5024103b07 | |||
| d0327807a7 | |||
| f880f1ba26 | |||
| 71dafc0c06 | |||
| 7d9357b871 | |||
| 0b02bbecd1 | |||
| 932a5cc8b4 | |||
| e4a321511a | |||
| 4ee5800ec9 | |||
| c67632225d | |||
| 6e45a376cd | |||
| 70b67cd2f1 | |||
| 304e89041c | |||
| f1a76efc2d | |||
| 963251314b | |||
| ee061f3659 | |||
| 440ffce2eb | |||
| 47871562ca | |||
| f0c548cee7 | |||
| 1a32b399e6 | |||
| e9f3da94fc | |||
| 4fb6f936a7 | |||
| c431b5479e | |||
| fc03950afd | |||
| 516b5fed4a | |||
| 165e29e585 | |||
| 0be3e86b21 | |||
| 96d229a6d1 | |||
| 5098cad9cf | |||
| 883c480af0 | |||
| 0f83e40427 | |||
| ad6ef6e4c7 | |||
| 94201e46f1 | |||
| 910e198cee | |||
| 45a88fc391 | |||
| 8f01efb9e3 | |||
| f53c65b3a0 | |||
| 0be772ff5b | |||
| ac990afa5d | |||
| 55cccbf727 | |||
| a095ea75a2 | |||
| a041e7c943 | |||
| 4f3072b3d9 | |||
| 13c467734a | |||
| c01b2b946b | |||
| 549f9dab64 | |||
| 58090c37ea | |||
| 38344e8de6 | |||
| 6f319f0b13 | |||
| 4e71b26ea4 | |||
| 04f3bbcefa | |||
| c67ee6f2a8 | |||
| 4b590ce31f | |||
| 5902b46e9b | |||
| 62449d6fa2 | |||
| aa06088077 | |||
| 2a60776c8a | |||
| f411ecada2 | |||
| 8eeacf4a36 | |||
| 20c252982e | |||
| 6c5ac0d8ec | |||
| e1cb375fbf | |||
| e7e3f06044 | |||
| 994e93741b | |||
| 04e1a11e35 | |||
| 547056d5cc | |||
| 1fa35fb9a8 | |||
| a49914e631 | |||
| 783a43ea35 | |||
| 07a176d11e | |||
| c664fbc1a3 | |||
| af412c4d65 | |||
| e38bf6e554 | |||
| 624e0da669 | |||
| b28aa6c647 | |||
| 9e83b4be25 | |||
| e9854c91ef | |||
| 0345e29afb | |||
| 8bd5795f8e | |||
| 4fbc98dcd2 | |||
| 44cdbd6cf3 | |||
| a9af8c4128 | |||
| 28c81af788 | |||
| 3a956daf0c | |||
| 9c245865d7 | |||
| 86ed937a47 | |||
| 32ec8c3ae4 | |||
| c7ffd2513a | |||
| b3e0f167ff | |||
| 8c063f8ccb | |||
| f1ca42e501 | |||
| 719149f01d | |||
| ccd30607a9 | |||
| aa1ef46d84 | |||
| 16a21264d0 | |||
| 1c0f092176 | |||
| 32d79f3f4e | |||
| 088a24cf59 |
@@ -5,14 +5,10 @@ on:
|
||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
workflow_dispatch: # Manual trigger
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update:
|
||||
name: Update Algolia Index
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v2
|
||||
|
||||
@@ -10,21 +10,12 @@ on:
|
||||
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
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
name: Backport Bot
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
push:
|
||||
branches:
|
||||
- '*.x'
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
- name: Download BackportBot
|
||||
run: wget https://github.com/spring-io/backport-bot/releases/download/latest/backport-bot-0.0.1-SNAPSHOT.jar
|
||||
- name: Backport
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_EVENT: ${{ toJSON(github.event) }}
|
||||
run: java -jar backport-bot-0.0.1-SNAPSHOT.jar --github.accessToken="$GITHUB_TOKEN" --github.event_name "$GITHUB_EVENT_NAME" --github.event "$GITHUB_EVENT"
|
||||
@@ -3,15 +3,9 @@ on:
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
permissions:
|
||||
contents: none
|
||||
steps:
|
||||
- name: Delete artifacts in cron job
|
||||
env:
|
||||
|
||||
@@ -2,8 +2,6 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
workflow_dispatch: # Manual trigger
|
||||
@@ -18,28 +16,19 @@ env:
|
||||
STRUCTURE101_LICENSEID: ${{ secrets.STRUCTURE101_LICENSEID }}
|
||||
ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
RUN_JOBS: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
|
||||
jobs:
|
||||
prerequisites:
|
||||
name: Pre-requisites for building
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
outputs:
|
||||
runjobs: ${{ steps.continue.outputs.runjobs }}
|
||||
project_version: ${{ steps.continue.outputs.project_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- id: continue
|
||||
name: Determine if should continue
|
||||
run: |
|
||||
# Run jobs if in upstream repository
|
||||
echo "::set-output name=runjobs::true"
|
||||
# Extract version from gradle.properties
|
||||
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
|
||||
echo "::set-output name=project_version::$version"
|
||||
if: env.RUN_JOBS == 'true'
|
||||
run: echo "::set-output name=runjobs::true"
|
||||
build_jdk_11:
|
||||
name: Build JDK 11
|
||||
needs: [prerequisites]
|
||||
@@ -51,14 +40,18 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Set up Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
- name: Set up gradle user name
|
||||
run: echo 'systemProp.user.name=spring-builds+github' >> gradle.properties
|
||||
- name: Setup gradle user name
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
|
||||
- name: Cache Gradle packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||
- name: Build with Gradle
|
||||
env:
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }}
|
||||
@@ -72,11 +65,14 @@ jobs:
|
||||
if: needs.prerequisites.outputs.runjobs
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Setup gradle user name
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
|
||||
- name: Snapshot Tests
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -90,11 +86,14 @@ jobs:
|
||||
if: needs.prerequisites.outputs.runjobs
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Setup gradle user name
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
|
||||
- name: Check samples project
|
||||
env:
|
||||
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
|
||||
@@ -112,11 +111,14 @@ jobs:
|
||||
if: needs.prerequisites.outputs.runjobs
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Setup gradle user name
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
|
||||
- name: Check for package tangles
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -129,11 +131,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Setup gradle user name
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
|
||||
- name: Deploy artifacts
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -153,11 +158,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Setup gradle user name
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
|
||||
- name: Deploy Docs
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -174,11 +182,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Setup gradle user name
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
|
||||
- name: Deploy Schema
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -189,122 +200,14 @@ jobs:
|
||||
DOCS_USERNAME: ${{ secrets.DOCS_USERNAME }}
|
||||
DOCS_SSH_KEY: ${{ secrets.DOCS_SSH_KEY }}
|
||||
DOCS_HOST: ${{ secrets.DOCS_HOST }}
|
||||
perform_release:
|
||||
name: Perform release
|
||||
needs: [prerequisites, deploy_artifacts, deploy_docs, deploy_schema]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
timeout-minutes: 90
|
||||
if: ${{ !endsWith(needs.prerequisites.outputs.project_version, '-SNAPSHOT') }}
|
||||
env:
|
||||
REPO: ${{ github.repository }}
|
||||
BRANCH: ${{ github.ref_name }}
|
||||
TOKEN: ${{ github.token }}
|
||||
VERSION: ${{ needs.prerequisites.outputs.project_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Wait for Artifactory Artifacts
|
||||
if: ${{ contains(needs.prerequisites.outputs.project_version, '-RC') || contains(needs.prerequisites.outputs.project_version, '-M') }}
|
||||
run: |
|
||||
echo "Wait for artifacts of $REPO@$VERSION to appear on Artifactory."
|
||||
until curl -f -s https://repo.spring.io/artifactory/milestone/org/springframework/security/spring-security-core/$VERSION/ > /dev/null
|
||||
do
|
||||
sleep 30
|
||||
echo "."
|
||||
done
|
||||
echo "Artifacts for $REPO@$VERSION have been released to Artifactory."
|
||||
- name: Wait for Maven Central Artifacts
|
||||
if: ${{ !contains(needs.prerequisites.outputs.project_version, '-RC') && !contains(needs.prerequisites.outputs.project_version, '-M') }}
|
||||
run: |
|
||||
echo "Wait for artifacts of $REPO@$VERSION to appear on Maven Central."
|
||||
until curl -f -s https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/$VERSION/ > /dev/null
|
||||
do
|
||||
sleep 30
|
||||
echo "."
|
||||
done
|
||||
echo "Artifacts for $REPO@$VERSION have been released to Maven Central."
|
||||
- name: Create GitHub Release
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
|
||||
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
|
||||
echo "Tagging and publishing $REPO@$VERSION release on GitHub."
|
||||
./gradlew createGitHubRelease -PnextVersion=$VERSION -Pbranch=$BRANCH -PcreateRelease=true -PgitHubAccessToken=$TOKEN
|
||||
- name: Announce Release on Slack
|
||||
id: spring-security-announcing
|
||||
uses: slackapi/slack-github-action@v1.19.0
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"text": "spring-security-announcing `${{ env.VERSION }}` is available now",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "spring-security-announcing `${{ env.VERSION }}` is available now"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SPRING_RELEASE_SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
- name: Setup git config
|
||||
run: |
|
||||
git config user.name 'github-actions[bot]'
|
||||
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
- name: Update to next Snapshot Version
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
|
||||
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
|
||||
echo "Updating $REPO@$VERSION to next snapshot version."
|
||||
./gradlew :updateToSnapshotVersion
|
||||
./gradlew :spring-security-docs:antoraUpdateVersion
|
||||
git commit -am "Next development version"
|
||||
git push
|
||||
perform_post_release:
|
||||
name: Perform post-release
|
||||
needs: [prerequisites, deploy_artifacts, deploy_docs, deploy_schema]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
timeout-minutes: 90
|
||||
if: ${{ endsWith(needs.prerequisites.outputs.project_version, '-SNAPSHOT') }}
|
||||
env:
|
||||
TOKEN: ${{ github.token }}
|
||||
VERSION: ${{ needs.prerequisites.outputs.project_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Schedule next release (if not already scheduled)
|
||||
run: ./gradlew scheduleNextRelease -PnextVersion=$VERSION -PgitHubAccessToken=$TOKEN
|
||||
notify_result:
|
||||
name: Check for failures
|
||||
needs: [perform_release, perform_post_release]
|
||||
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles, deploy_artifacts, deploy_docs, deploy_schema]
|
||||
if: failure()
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
steps:
|
||||
- name: Send Slack message
|
||||
# Workaround while waiting for Gamesight/slack-workflow-status#38 to be fixed
|
||||
# See https://github.com/Gamesight/slack-workflow-status/issues/38
|
||||
uses: sjohnr/slack-workflow-status@v1-beta
|
||||
uses: Gamesight/slack-workflow-status@v1.0.1
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
|
||||
@@ -7,28 +7,27 @@ on:
|
||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
workflow_dispatch: # Manual trigger
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: deploy
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
- 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 /home/runner/.gradle/caches/modules-2/modules-2.lock
|
||||
rm -f /home/runner/.gradle/caches/modules-2/gc.properties
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew :spring-security-docs:antora --stacktrace
|
||||
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 }}"
|
||||
|
||||
@@ -5,15 +5,10 @@ on:
|
||||
env:
|
||||
DUE_ON: ${{ github.event.milestone.due_on }}
|
||||
TITLE: ${{ github.event.milestone.title }}
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
spring-releasetrain-checks:
|
||||
name: Check DueOn is on a Release Date
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
permissions:
|
||||
contents: none
|
||||
steps:
|
||||
- name: Print Milestone Being Checked
|
||||
run: echo "Validating DueOn '$DUE_ON' for milestone '$TITLE'"
|
||||
@@ -28,8 +23,6 @@ jobs:
|
||||
needs: [spring-releasetrain-checks]
|
||||
if: failure()
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
steps:
|
||||
- name: Send Slack message
|
||||
uses: Gamesight/slack-workflow-status@v1.0.1
|
||||
|
||||
@@ -2,20 +2,27 @@ name: PR Build
|
||||
|
||||
on: pull_request
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
RUN_JOBS: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
- if: env.RUN_JOBS == 'true'
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up JDK
|
||||
if: env.RUN_JOBS == 'true'
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Cache Gradle packages
|
||||
if: env.RUN_JOBS == 'true'
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||
- name: Build with Gradle
|
||||
if: env.RUN_JOBS == 'true'
|
||||
run: ./gradlew clean build --continue --scan
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
name: Update Scheduled Release Version
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Manual trigger only. Triggered by release-scheduler.yml on main.
|
||||
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
GRADLE_ENTERPRISE_CACHE_USER: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }}
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update_scheduled_release_version:
|
||||
name: Initiate Release If Scheduled
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
steps:
|
||||
- id: checkout-source
|
||||
name: Checkout Source Code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- id: check-release-due
|
||||
name: Check Release Due
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
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)"
|
||||
- id: check-open-issues
|
||||
name: Check for open issues
|
||||
if: steps.check-release-due.outputs.is_due_today == 'true'
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
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)"
|
||||
- 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'
|
||||
run: |
|
||||
echo "The release is due today but there are open issues"
|
||||
exit 1
|
||||
- id: update-version-and-push
|
||||
name: Update version and push
|
||||
if: steps.check-release-due.outputs.is_due_today == 'true' && steps.check-open-issues.outputs.is_open_issues == 'false'
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
|
||||
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
|
||||
git config user.name 'github-actions[bot]'
|
||||
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
./gradlew :updateProjectVersion
|
||||
./gradlew :spring-security-docs:antoraUpdateVersion
|
||||
updatedVersion=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
|
||||
git commit -am "Release $updatedVersion"
|
||||
git tag $updatedVersion
|
||||
git push
|
||||
git push origin $updatedVersion
|
||||
- id: send-slack-notification
|
||||
name: Send Slack message
|
||||
if: failure()
|
||||
uses: Gamesight/slack-workflow-status@v1.0.1
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
channel: '#spring-security-ci'
|
||||
name: 'CI Notifier'
|
||||
+1
-1
@@ -135,7 +135,7 @@ git push origin 5.4.0-RC1
|
||||
|
||||
The following command will update https://spring.io/projects/spring-security#learn with the new release version using the following parameters
|
||||
|
||||
<github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `read:org` as https://spring.io/restdocs/index.html#authentication[documented for spring.io api]
|
||||
<github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`
|
||||
<next-version> - Replace with the milestone you are releasing now (i.e. 5.5.0-RC1)
|
||||
<previous-version> - Replace with the previous release which will be removed from the listed versions (i.e. 5.5.0-M3)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.springframework.security.acls.domain.AuditLogger;
|
||||
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.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PermissionFactory;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
@@ -51,7 +51,6 @@ import org.springframework.security.acls.model.AclCache;
|
||||
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;
|
||||
@@ -74,8 +73,8 @@ import org.springframework.util.Assert;
|
||||
* one in <tt>lookupObjectIdentities</tt>. These are built from the same select and "order
|
||||
* by" clause, using a different where clause in each case. In order to use custom schema
|
||||
* or column names, each of these SQL clauses can be customized, but they must be
|
||||
* consistent with each other and with the expected result set generated by the default
|
||||
* values.
|
||||
* consistent with each other and with the expected result set generated by the the
|
||||
* default values.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
@@ -110,8 +109,6 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
private final AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
private ObjectIdentityGenerator objectIdentityGenerator;
|
||||
|
||||
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
private final AclCache aclCache;
|
||||
@@ -165,7 +162,6 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
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);
|
||||
@@ -492,11 +488,6 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -578,8 +569,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
// target id type, e.g. UUID.
|
||||
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
|
||||
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
|
||||
ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator
|
||||
.createObjectIdentity(identifier, rs.getString("class"));
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"), identifier);
|
||||
|
||||
Acl parentAcl = null;
|
||||
long parentAclId = rs.getLong("parent_object");
|
||||
|
||||
@@ -31,12 +31,11 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
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;
|
||||
|
||||
@@ -82,8 +81,6 @@ public class JdbcAclService implements AclService {
|
||||
|
||||
private AclClassIdUtils aclClassIdUtils;
|
||||
|
||||
private ObjectIdentityGenerator objectIdentityGenerator;
|
||||
|
||||
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
|
||||
this(new JdbcTemplate(dataSource), lookupStrategy);
|
||||
}
|
||||
@@ -94,7 +91,6 @@ public class JdbcAclService implements AclService {
|
||||
this.jdbcOperations = jdbcOperations;
|
||||
this.lookupStrategy = lookupStrategy;
|
||||
this.aclClassIdUtils = new AclClassIdUtils();
|
||||
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,7 +105,7 @@ public class JdbcAclService implements AclService {
|
||||
String javaType = rs.getString("class");
|
||||
Serializable identifier = (Serializable) rs.getObject("obj_id");
|
||||
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
|
||||
return this.objectIdentityGenerator.createObjectIdentity(identifier, javaType);
|
||||
return new ObjectIdentityImpl(javaType, identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,11 +165,6 @@ public class JdbcAclService implements AclService {
|
||||
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;
|
||||
}
|
||||
|
||||
-9
@@ -318,13 +318,4 @@ public abstract class AbstractBasicLookupStrategyTests {
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ import org.springframework.security.acls.model.Sid;
|
||||
|
||||
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;
|
||||
@@ -171,26 +170,6 @@ public class JdbcAclServiceTests {
|
||||
.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<ObjectIdentity> 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;
|
||||
|
||||
@@ -27,3 +27,7 @@ sourceSets.test.aspectj.srcDir "src/test/java"
|
||||
sourceSets.test.java.srcDirs = files()
|
||||
|
||||
compileAspectj.ajcOptions.outxmlfile = "META-INF/aop.xml"
|
||||
|
||||
aspectj {
|
||||
version = aspectjVersion
|
||||
}
|
||||
|
||||
+4
-54
@@ -2,12 +2,13 @@ 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.4.3.1"
|
||||
classpath "io.freefair.gradle:aspectj-plugin:6.2.0"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||
classpath "com.netflix.nebula:nebula-project-plugin:8.2.0"
|
||||
}
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven { url 'https://repo.spring.io/plugins-snapshot' }
|
||||
maven { url 'https://plugins.gradle.org/m2/' }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +19,9 @@ apply plugin: 'io.spring.convention.root'
|
||||
apply plugin: 'io.spring.convention.include-check-remote'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'org.springframework.security.update-dependencies'
|
||||
apply plugin: 'org.springframework.security.update-version'
|
||||
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'
|
||||
@@ -47,43 +46,6 @@ tasks.named("gitHubCheckMilestoneHasNoOpenIssues") {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("gitHubNextReleaseMilestone") {
|
||||
repository {
|
||||
owner = "spring-projects"
|
||||
name = "spring-security"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("gitHubCheckNextVersionDueToday") {
|
||||
repository {
|
||||
owner = "spring-projects"
|
||||
name = "spring-security"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("scheduleNextRelease") {
|
||||
repository {
|
||||
owner = "spring-projects"
|
||||
name = "spring-security"
|
||||
}
|
||||
weekOfMonth = 3
|
||||
dayOfWeek = 1
|
||||
}
|
||||
|
||||
tasks.named("createGitHubRelease") {
|
||||
repository {
|
||||
owner = "spring-projects"
|
||||
name = "spring-security"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("dispatchGitHubWorkflow") {
|
||||
repository {
|
||||
owner = "spring-projects"
|
||||
name = "spring-security"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("updateDependencies") {
|
||||
// we aren't Gradle 7 compatible yet
|
||||
checkForGradleUpdate = false
|
||||
@@ -102,9 +64,9 @@ updateDependenciesSettings {
|
||||
dependencyExcludes {
|
||||
majorVersionBump()
|
||||
minorVersionBump()
|
||||
alphaBetaVersions()
|
||||
releaseCandidatesVersions()
|
||||
milestoneVersions()
|
||||
alphaBetaVersions()
|
||||
snapshotVersions()
|
||||
addRule { components ->
|
||||
components.withModule("commons-codec:commons-codec") { selection ->
|
||||
@@ -133,18 +95,6 @@ updateDependenciesSettings {
|
||||
selection.reject("org.opensaml maintains two different versions, so it must be updated manually");
|
||||
}
|
||||
}
|
||||
components.withModule("io.spring.javaformat:spring-javaformat-gradle-plugin") { selection ->
|
||||
ModuleComponentIdentifier candidate = selection.getCandidate();
|
||||
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
|
||||
selection.reject("spring-javaformat-gradle-plugin updates break checkstyle");
|
||||
}
|
||||
}
|
||||
components.withModule("io.spring.javaformat:spring-javaformat-checkstyle") { selection ->
|
||||
ModuleComponentIdentifier candidate = selection.getCandidate();
|
||||
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
|
||||
selection.reject("spring-javaformat-checkstyle updates break checkstyle");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-11
@@ -5,6 +5,7 @@ plugins {
|
||||
id 'com.apollographql.apollo' version '2.4.5'
|
||||
}
|
||||
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
@@ -28,7 +29,7 @@ gradlePlugin {
|
||||
plugins {
|
||||
checkAntoraVersion {
|
||||
id = "org.springframework.antora.check-version"
|
||||
implementationClass = "org.springframework.gradle.antora.AntoraVersionPlugin"
|
||||
implementationClass = "org.springframework.gradle.antora.CheckAntoraVersionPlugin"
|
||||
}
|
||||
trang {
|
||||
id = "trang"
|
||||
@@ -46,10 +47,6 @@ gradlePlugin {
|
||||
id = "org.springframework.security.update-dependencies"
|
||||
implementationClass = "org.springframework.security.convention.versions.UpdateDependenciesPlugin"
|
||||
}
|
||||
updateProjectVersion {
|
||||
id = "org.springframework.security.update-version"
|
||||
implementationClass = "org.springframework.security.convention.versions.UpdateProjectVersionPlugin"
|
||||
}
|
||||
sagan {
|
||||
id = "org.springframework.security.sagan"
|
||||
implementationClass = "org.springframework.gradle.sagan.SaganPlugin"
|
||||
@@ -62,10 +59,6 @@ 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"
|
||||
@@ -87,7 +80,7 @@ dependencies {
|
||||
implementation localGroovy()
|
||||
|
||||
implementation 'io.github.gradle-nexus:publish-plugin:1.1.0'
|
||||
implementation 'io.projectreactor:reactor-core:3.5.0-M1'
|
||||
implementation 'io.projectreactor:reactor-core:3.4.18'
|
||||
implementation 'gradle.plugin.org.gretty:gretty:3.0.1'
|
||||
implementation 'com.apollographql.apollo:apollo-runtime:2.4.5'
|
||||
implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
|
||||
@@ -96,7 +89,7 @@ dependencies {
|
||||
implementation 'io.spring.nohttp:nohttp-gradle:0.0.10'
|
||||
implementation 'net.sourceforge.htmlunit:htmlunit:2.37.0'
|
||||
implementation 'org.hidetake:gradle-ssh-plugin:2.10.1'
|
||||
implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.29.0'
|
||||
implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.24.20'
|
||||
implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'
|
||||
|
||||
testImplementation platform('org.junit:junit-bom:5.8.2')
|
||||
|
||||
@@ -17,7 +17,6 @@ package io.spring.gradle.convention
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
|
||||
|
||||
class ArtifactoryPlugin implements Plugin<Project> {
|
||||
|
||||
@@ -37,14 +36,8 @@ class ArtifactoryPlugin implements Plugin<Project> {
|
||||
password = artifactoryPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
project.plugins.withType(MavenPublishPlugin) {
|
||||
project.artifactory {
|
||||
publish {
|
||||
defaults {
|
||||
publications('mavenJava')
|
||||
}
|
||||
defaults {
|
||||
publications('mavenJava')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,22 +59,14 @@ public class IntegrationTestPlugin implements Plugin<Project> {
|
||||
integrationTestRuntime {
|
||||
extendsFrom integrationTestCompile, testRuntime, testRuntimeOnly
|
||||
}
|
||||
integrationTestCompileClasspath {
|
||||
extendsFrom integrationTestCompile
|
||||
canBeResolved = true
|
||||
}
|
||||
integrationTestRuntimeClasspath {
|
||||
extendsFrom integrationTestRuntime
|
||||
canBeResolved = true
|
||||
}
|
||||
}
|
||||
|
||||
project.sourceSets {
|
||||
integrationTest {
|
||||
java.srcDir project.file('src/integration-test/java')
|
||||
resources.srcDir project.file('src/integration-test/resources')
|
||||
compileClasspath = project.sourceSets.main.output + project.sourceSets.test.output + project.configurations.integrationTestCompileClasspath
|
||||
runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntimeClasspath
|
||||
compileClasspath = project.sourceSets.main.output + project.sourceSets.test.output + project.configurations.integrationTestCompile
|
||||
runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntime
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +85,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
|
||||
project.idea {
|
||||
module {
|
||||
testSourceDirs += project.file('src/integration-test/java')
|
||||
scopes.TEST.plus += [ project.configurations.integrationTestCompileClasspath ]
|
||||
scopes.TEST.plus += [ project.configurations.integrationTestCompile ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +115,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
|
||||
|
||||
project.plugins.withType(EclipsePlugin) {
|
||||
project.eclipse.classpath {
|
||||
plusConfigurations += [ project.configurations.integrationTestCompileClasspath ]
|
||||
plusConfigurations += [ project.configurations.integrationTestCompile ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ class RootProjectPlugin implements Plugin<Project> {
|
||||
pluginManager.apply(NoHttpPlugin)
|
||||
pluginManager.apply(SpringNexusPublishPlugin)
|
||||
pluginManager.apply(CheckProhibitedDependenciesLifecyclePlugin)
|
||||
pluginManager.apply(ArtifactoryPlugin)
|
||||
pluginManager.apply("org.sonarqube")
|
||||
|
||||
project.repositories.mavenCentral()
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.gradle.antora;
|
||||
|
||||
public class AntoraVersionUtils {
|
||||
|
||||
public static String getDefaultAntoraVersion(String projectVersion) {
|
||||
int preReleaseIndex = getSnapshotIndex(projectVersion);
|
||||
return isSnapshot(projectVersion) ? projectVersion.substring(0, preReleaseIndex) : projectVersion;
|
||||
}
|
||||
|
||||
public static String getDefaultAntoraPrerelease(String projectVersion) {
|
||||
if (isSnapshot(projectVersion)) {
|
||||
int preReleaseIndex = getSnapshotIndex(projectVersion);
|
||||
return projectVersion.substring(preReleaseIndex);
|
||||
}
|
||||
if (isPreRelease(projectVersion)) {
|
||||
return Boolean.TRUE.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getDefaultAntoraDisplayVersion(String projectVersion) {
|
||||
if (!isSnapshot(projectVersion) && isPreRelease(projectVersion)) {
|
||||
return getDefaultAntoraVersion(projectVersion);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isSnapshot(String projectVersion) {
|
||||
return getSnapshotIndex(projectVersion) >= 0;
|
||||
}
|
||||
|
||||
private static int getSnapshotIndex(String projectVersion) {
|
||||
return projectVersion.lastIndexOf("-SNAPSHOT");
|
||||
}
|
||||
|
||||
private static boolean isPreRelease(String projectVersion) {
|
||||
return projectVersion.lastIndexOf("-") >= 0;
|
||||
}
|
||||
}
|
||||
+26
-12
@@ -8,7 +8,7 @@ import org.gradle.api.Task;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin;
|
||||
|
||||
public class AntoraVersionPlugin implements Plugin<Project> {
|
||||
public class CheckAntoraVersionPlugin implements Plugin<Project> {
|
||||
public static final String ANTORA_CHECK_VERSION_TASK_NAME = "antoraCheckVersion";
|
||||
|
||||
@Override
|
||||
@@ -35,29 +35,32 @@ public class AntoraVersionPlugin implements Plugin<Project> {
|
||||
});
|
||||
}
|
||||
});
|
||||
project.getTasks().register("antoraUpdateVersion", UpdateAntoraVersionTask.class, new Action<UpdateAntoraVersionTask>() {
|
||||
@Override
|
||||
public void execute(UpdateAntoraVersionTask antoraUpdateVersion) {
|
||||
antoraUpdateVersion.setGroup("Release");
|
||||
antoraUpdateVersion.setDescription("Updates the antora.yml version properties to match the Gradle version");
|
||||
antoraUpdateVersion.getAntoraYmlFile().fileProvider(project.provider(() -> project.file("antora.yml")));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static String getDefaultAntoraVersion(Project project) {
|
||||
String projectVersion = getProjectVersion(project);
|
||||
return AntoraVersionUtils.getDefaultAntoraVersion(projectVersion);
|
||||
int preReleaseIndex = getSnapshotIndex(projectVersion);
|
||||
return isSnapshot(projectVersion) ? projectVersion.substring(0, preReleaseIndex) : projectVersion;
|
||||
}
|
||||
|
||||
private static String getDefaultAntoraPrerelease(Project project) {
|
||||
String projectVersion = getProjectVersion(project);
|
||||
return AntoraVersionUtils.getDefaultAntoraPrerelease(projectVersion);
|
||||
if (isSnapshot(projectVersion)) {
|
||||
int preReleaseIndex = getSnapshotIndex(projectVersion);
|
||||
return projectVersion.substring(preReleaseIndex);
|
||||
}
|
||||
if (isPreRelease(projectVersion)) {
|
||||
return Boolean.TRUE.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getDefaultAntoraDisplayVersion(Project project) {
|
||||
String projectVersion = getProjectVersion(project);
|
||||
return AntoraVersionUtils.getDefaultAntoraDisplayVersion(projectVersion);
|
||||
if (!isSnapshot(projectVersion) && isPreRelease(projectVersion)) {
|
||||
return getDefaultAntoraVersion(project);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getProjectVersion(Project project) {
|
||||
@@ -68,4 +71,15 @@ public class AntoraVersionPlugin implements Plugin<Project> {
|
||||
return String.valueOf(projectVersion);
|
||||
}
|
||||
|
||||
private static boolean isSnapshot(String projectVersion) {
|
||||
return getSnapshotIndex(projectVersion) >= 0;
|
||||
}
|
||||
|
||||
private static int getSnapshotIndex(String projectVersion) {
|
||||
return projectVersion.lastIndexOf("-SNAPSHOT");
|
||||
}
|
||||
|
||||
private static boolean isPreRelease(String projectVersion) {
|
||||
return projectVersion.lastIndexOf("-") >= 0;
|
||||
}
|
||||
}
|
||||
-138
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.gradle.antora;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.nodes.NodeTuple;
|
||||
import org.yaml.snakeyaml.nodes.Tag;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.gradle.github.milestones.NextVersionYml;
|
||||
|
||||
public abstract class UpdateAntoraVersionTask extends DefaultTask {
|
||||
|
||||
@TaskAction
|
||||
public void update() throws IOException {
|
||||
String projectVersion = getProject().getVersion().toString();
|
||||
File antoraYmlFile = getAntoraYmlFile().getAsFile().get();
|
||||
String updatedAntoraVersion = AntoraVersionUtils.getDefaultAntoraVersion(projectVersion);
|
||||
String updatedAntoraPrerelease = AntoraVersionUtils.getDefaultAntoraPrerelease(projectVersion);
|
||||
String updatedAntoraDisplayVersion = AntoraVersionUtils.getDefaultAntoraDisplayVersion(projectVersion);
|
||||
|
||||
Representer representer = new Representer();
|
||||
representer.getPropertyUtils().setSkipMissingProperties(true);
|
||||
|
||||
Yaml yaml = new Yaml(new Constructor(AntoraYml.class), representer);
|
||||
AntoraYml antoraYml = yaml.load(new FileInputStream(antoraYmlFile));
|
||||
|
||||
System.out.println("Updating the version parameters in " + antoraYmlFile.getName() + " to version: "
|
||||
+ updatedAntoraVersion + ", prerelease: " + updatedAntoraPrerelease + ", display_version: "
|
||||
+ updatedAntoraDisplayVersion);
|
||||
antoraYml.setVersion(updatedAntoraVersion);
|
||||
antoraYml.setPrerelease(updatedAntoraPrerelease);
|
||||
antoraYml.setDisplay_version(updatedAntoraDisplayVersion);
|
||||
|
||||
FileWriter outputWriter = new FileWriter(antoraYmlFile);
|
||||
getYaml().dump(antoraYml, outputWriter);
|
||||
}
|
||||
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getAntoraYmlFile();
|
||||
|
||||
public static class AntoraYml {
|
||||
|
||||
private String name;
|
||||
|
||||
private String version;
|
||||
|
||||
private String prerelease;
|
||||
|
||||
private String display_version;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getPrerelease() {
|
||||
return prerelease;
|
||||
}
|
||||
|
||||
public void setPrerelease(String prerelease) {
|
||||
this.prerelease = prerelease;
|
||||
}
|
||||
|
||||
public String getDisplay_version() {
|
||||
return display_version;
|
||||
}
|
||||
|
||||
public void setDisplay_version(String display_version) {
|
||||
this.display_version = display_version;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Yaml getYaml() {
|
||||
Representer representer = new Representer() {
|
||||
@Override
|
||||
protected NodeTuple representJavaBeanProperty(Object javaBean,
|
||||
org.yaml.snakeyaml.introspector.Property property, Object propertyValue, Tag customTag) {
|
||||
// Don't write out null values
|
||||
if (propertyValue == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
|
||||
}
|
||||
}
|
||||
};
|
||||
representer.addClassTag(AntoraYml.class, Tag.MAP);
|
||||
DumperOptions ymlOptions = new DumperOptions();
|
||||
ymlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
ymlOptions.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
|
||||
return new Yaml(representer, ymlOptions);
|
||||
}
|
||||
|
||||
}
|
||||
+4
-5
@@ -16,9 +16,6 @@
|
||||
|
||||
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;
|
||||
@@ -31,10 +28,12 @@ import org.gradle.api.artifacts.repositories.IvyArtifactRepository;
|
||||
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<Project> {
|
||||
|
||||
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) {
|
||||
@@ -43,7 +42,7 @@ public class GitHubChangelogPlugin implements Plugin<Project> {
|
||||
project.getTasks().register("generateChangelog", JavaExec.class, new Action<JavaExec>() {
|
||||
@Override
|
||||
public void execute(JavaExec generateChangelog) {
|
||||
File outputFile = project.file(Paths.get(project.getBuildDir().getPath(), RELEASE_NOTES_PATH));
|
||||
File outputFile = project.file(Paths.get(project.getBuildDir().getPath(), "changelog/release-notes.md"));
|
||||
outputFile.getParentFile().mkdirs();
|
||||
generateChangelog.setGroup("Release");
|
||||
generateChangelog.setDescription("Generates the changelog");
|
||||
|
||||
+19
-176
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,35 +16,22 @@
|
||||
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class GitHubMilestoneApi {
|
||||
private String baseUrl = "https://api.github.com";
|
||||
|
||||
private OkHttpClient client;
|
||||
|
||||
private final Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(LocalDate.class, new LocalDateAdapter().nullSafe())
|
||||
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter().nullSafe())
|
||||
.create();
|
||||
private Gson gson = new Gson();
|
||||
|
||||
public GitHubMilestoneApi() {
|
||||
this.client = new OkHttpClient.Builder().build();
|
||||
@@ -61,30 +48,26 @@ public class GitHubMilestoneApi {
|
||||
}
|
||||
|
||||
public long findMilestoneNumberByTitle(RepositoryRef repositoryRef, String milestoneTitle) {
|
||||
List<Milestone> milestones = this.getMilestones(repositoryRef);
|
||||
for (Milestone milestone : milestones) {
|
||||
if (milestoneTitle.equals(milestone.getTitle())) {
|
||||
return milestone.getNumber();
|
||||
}
|
||||
}
|
||||
if (milestones.size() <= 100) {
|
||||
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
|
||||
}
|
||||
throw new RuntimeException("It is possible there are too many open milestones (only 100 are supported). Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
|
||||
}
|
||||
|
||||
public List<Milestone> getMilestones(RepositoryRef repositoryRef) {
|
||||
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/milestones?per_page=100";
|
||||
Request request = new Request.Builder().get().url(url)
|
||||
.build();
|
||||
try {
|
||||
Response response = this.client.newCall(request).execute();
|
||||
if (!response.isSuccessful()) {
|
||||
throw new RuntimeException("Could not retrieve milestones for repository " + repositoryRef + ". Response " + response);
|
||||
throw new RuntimeException("Could not find milestone with title " + milestoneTitle + " for repository " + repositoryRef + ". Response " + response);
|
||||
}
|
||||
return this.gson.fromJson(response.body().charStream(), new TypeToken<List<Milestone>>(){}.getType());
|
||||
List<Milestone> milestones = this.gson.fromJson(response.body().charStream(), new TypeToken<List<Milestone>>(){}.getType());
|
||||
for (Milestone milestone : milestones) {
|
||||
if (milestoneTitle.equals(milestone.getTitle())) {
|
||||
return milestone.getNumber();
|
||||
}
|
||||
}
|
||||
if (milestones.size() <= 100) {
|
||||
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
|
||||
}
|
||||
throw new RuntimeException("It is possible there are too many open milestones open (only 100 are supported). Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not retrieve milestones for repository " + repositoryRef, e);
|
||||
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,150 +87,10 @@ public class GitHubMilestoneApi {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given milestone is due today or past due.
|
||||
*
|
||||
* @param repositoryRef The repository owner/name
|
||||
* @param milestoneTitle The title of the milestone whose due date should be checked
|
||||
* @return true if the given milestone is due today or past due, false otherwise
|
||||
*/
|
||||
public boolean isMilestoneDueToday(RepositoryRef repositoryRef, String milestoneTitle) {
|
||||
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName()
|
||||
+ "/milestones?per_page=100";
|
||||
Request request = new Request.Builder().get().url(url).build();
|
||||
try {
|
||||
Response response = this.client.newCall(request).execute();
|
||||
if (!response.isSuccessful()) {
|
||||
throw new RuntimeException("Could not find milestone with title " + milestoneTitle + " for repository "
|
||||
+ repositoryRef + ". Response " + response);
|
||||
}
|
||||
List<Milestone> milestones = this.gson.fromJson(response.body().charStream(),
|
||||
new TypeToken<List<Milestone>>() {
|
||||
}.getType());
|
||||
for (Milestone milestone : milestones) {
|
||||
if (milestoneTitle.equals(milestone.getTitle())) {
|
||||
LocalDate today = LocalDate.now();
|
||||
return milestone.getDueOn() != null && today.compareTo(milestone.getDueOn().toLocalDate()) >= 0;
|
||||
}
|
||||
}
|
||||
if (milestones.size() <= 100) {
|
||||
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle
|
||||
+ " for repository " + repositoryRef + " Got " + milestones);
|
||||
}
|
||||
throw new RuntimeException(
|
||||
"It is possible there are too many open milestones open (only 100 are supported). Could not find open milestone with title "
|
||||
+ milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef,
|
||||
e);
|
||||
}
|
||||
}
|
||||
// public boolean isOpenIssuesForMilestoneName(String owner, String repository, String milestoneName) {
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* Calculate the next release version based on the current version.
|
||||
*
|
||||
* The current version must conform to the pattern MAJOR.MINOR.PATCH-SNAPSHOT. If the
|
||||
* current version is a snapshot of a patch release, then the patch release will be
|
||||
* returned. For example, if the current version is 5.6.1-SNAPSHOT, then 5.6.1 will be
|
||||
* returned. If the current version is a snapshot of a version that is not GA (i.e the
|
||||
* PATCH segment is 0), then GitHub will be queried to find the next milestone or
|
||||
* release candidate. If no pre-release versions are found, then the next version will
|
||||
* be assumed to be the GA.
|
||||
* @param repositoryRef The repository owner/name
|
||||
* @param currentVersion The current project version
|
||||
* @return the next matching milestone/release candidate or null if none exist
|
||||
*/
|
||||
public String getNextReleaseMilestone(RepositoryRef repositoryRef, String currentVersion) {
|
||||
Pattern snapshotPattern = Pattern.compile("^([0-9]+)\\.([0-9]+)\\.([0-9]+)-SNAPSHOT$");
|
||||
Matcher snapshotVersion = snapshotPattern.matcher(currentVersion);
|
||||
|
||||
if (snapshotVersion.find()) {
|
||||
String patchSegment = snapshotVersion.group(3);
|
||||
String currentVersionNoIdentifier = currentVersion.replace("-SNAPSHOT", "");
|
||||
if (patchSegment.equals("0")) {
|
||||
String nextPreRelease = getNextPreRelease(repositoryRef, currentVersionNoIdentifier);
|
||||
return nextPreRelease != null ? nextPreRelease : currentVersionNoIdentifier;
|
||||
}
|
||||
else {
|
||||
return currentVersionNoIdentifier;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Cannot calculate next release version because the current project version does not conform to the expected format");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the next pre-release version (milestone or release candidate) based on
|
||||
* the current version.
|
||||
*
|
||||
* The current version must conform to the pattern MAJOR.MINOR.PATCH. If no matching
|
||||
* milestone or release candidate is found in GitHub then it will return null.
|
||||
* @param repositoryRef The repository owner/name
|
||||
* @param currentVersionNoIdentifier The current project version without any
|
||||
* identifier
|
||||
* @return the next matching milestone/release candidate or null if none exist
|
||||
*/
|
||||
private String getNextPreRelease(RepositoryRef repositoryRef, String currentVersionNoIdentifier) {
|
||||
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName()
|
||||
+ "/milestones?per_page=100";
|
||||
Request request = new Request.Builder().get().url(url).build();
|
||||
try {
|
||||
Response response = this.client.newCall(request).execute();
|
||||
if (!response.isSuccessful()) {
|
||||
throw new RuntimeException(
|
||||
"Could not get milestones for repository " + repositoryRef + ". Response " + response);
|
||||
}
|
||||
List<Milestone> milestones = this.gson.fromJson(response.body().charStream(),
|
||||
new TypeToken<List<Milestone>>() {
|
||||
}.getType());
|
||||
Optional<String> nextPreRelease = milestones.stream().map(Milestone::getTitle)
|
||||
.filter(m -> m.startsWith(currentVersionNoIdentifier + "-"))
|
||||
.min((m1, m2) -> {
|
||||
Pattern preReleasePattern = Pattern.compile("^.*-([A-Z]+)([0-9]+)$");
|
||||
Matcher matcher1 = preReleasePattern.matcher(m1);
|
||||
Matcher matcher2 = preReleasePattern.matcher(m2);
|
||||
matcher1.find();
|
||||
matcher2.find();
|
||||
if (!matcher1.group(1).equals(matcher2.group(1))) {
|
||||
return m1.compareTo(m2);
|
||||
}
|
||||
else {
|
||||
return Integer.valueOf(matcher1.group(2)).compareTo(Integer.valueOf(matcher2.group(2)));
|
||||
}
|
||||
});
|
||||
return nextPreRelease.orElse(null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("Could not find open milestones with for repository " + repositoryRef, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a milestone.
|
||||
*
|
||||
* @param repository The repository owner/name
|
||||
* @param milestone The milestone containing a title and due date
|
||||
*/
|
||||
public void createMilestone(RepositoryRef repository, Milestone milestone) {
|
||||
String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/milestones";
|
||||
String json = this.gson.toJson(milestone);
|
||||
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
|
||||
Request request = new Request.Builder().url(url).post(body).build();
|
||||
try {
|
||||
Response response = this.client.newCall(request).execute();
|
||||
if (!response.isSuccessful()) {
|
||||
throw new RuntimeException(String.format("Could not create milestone %s for repository %s/%s. Got response %s",
|
||||
milestone.getTitle(), repository.getOwner(), repository.getName(), response));
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(String.format("Could not create release %s for repository %s/%s",
|
||||
milestone.getTitle(), repository.getOwner(), repository.getName()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AuthorizationInterceptor implements Interceptor {
|
||||
|
||||
|
||||
+6
-42
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,66 +17,30 @@ package org.springframework.gradle.github.milestones;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.work.DisableCachingByDefault;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
|
||||
@DisableCachingByDefault(because = "the due date needs to be checked every time in case it changes")
|
||||
public abstract class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask {
|
||||
public class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask {
|
||||
@Input
|
||||
private RepositoryRef repository = new RepositoryRef();
|
||||
|
||||
@Input @Optional
|
||||
@Input
|
||||
private String milestoneTitle;
|
||||
|
||||
@InputFile @Optional
|
||||
public abstract RegularFileProperty getNextVersionFile();
|
||||
|
||||
@Input @Optional
|
||||
private String gitHubAccessToken;
|
||||
|
||||
@OutputFile
|
||||
public abstract RegularFileProperty getIsOpenIssuesFile();
|
||||
|
||||
private GitHubMilestoneApi milestones = new GitHubMilestoneApi();
|
||||
|
||||
@TaskAction
|
||||
public void checkHasNoOpenIssues() throws IOException {
|
||||
if (this.milestoneTitle == null) {
|
||||
File nextVersionFile = getNextVersionFile().getAsFile().get();
|
||||
Yaml yaml = new Yaml(new Constructor(NextVersionYml.class));
|
||||
NextVersionYml nextVersionYml = yaml.load(new FileInputStream(nextVersionFile));
|
||||
String nextVersion = nextVersionYml.getVersion();
|
||||
if (nextVersion == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not find version property in provided file " + nextVersionFile.getName());
|
||||
}
|
||||
this.milestoneTitle = nextVersion;
|
||||
}
|
||||
public void checkHasNoOpenIssues() {
|
||||
long milestoneNumber = this.milestones.findMilestoneNumberByTitle(this.repository, this.milestoneTitle);
|
||||
boolean isOpenIssues = this.milestones.isOpenIssuesForMilestoneNumber(this.repository, milestoneNumber);
|
||||
Path isOpenIssuesPath = getIsOpenIssuesFile().getAsFile().get().toPath();
|
||||
Files.write(isOpenIssuesPath, String.valueOf(isOpenIssues).getBytes());
|
||||
if (isOpenIssues) {
|
||||
System.out.println("The repository " + this.repository + " has open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
|
||||
}
|
||||
else {
|
||||
System.out.println("The repository " + this.repository + " has no open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
|
||||
throw new IllegalStateException("The repository " + this.repository + " has open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
|
||||
}
|
||||
System.out.println("The repository " + this.repository + " has no open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
|
||||
}
|
||||
|
||||
public RepositoryRef getRepository() {
|
||||
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.gradle.github.milestones;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.nodes.Tag;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
|
||||
public abstract class GitHubMilestoneNextReleaseTask extends DefaultTask {
|
||||
|
||||
@Input
|
||||
private RepositoryRef repository = new RepositoryRef();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
private String gitHubAccessToken;
|
||||
|
||||
private GitHubMilestoneApi milestones = new GitHubMilestoneApi();
|
||||
|
||||
@TaskAction
|
||||
public void calculateNextReleaseMilestone() throws IOException {
|
||||
String currentVersion = getProject().getVersion().toString();
|
||||
String nextPreRelease = this.milestones.getNextReleaseMilestone(this.repository, currentVersion);
|
||||
System.out.println("The next release milestone is: " + nextPreRelease);
|
||||
NextVersionYml nextVersionYml = new NextVersionYml();
|
||||
nextVersionYml.setVersion(nextPreRelease);
|
||||
File outputFile = getNextReleaseFile().get().getAsFile();
|
||||
FileWriter outputWriter = new FileWriter(outputFile);
|
||||
Yaml yaml = getYaml();
|
||||
yaml.dump(nextVersionYml, outputWriter);
|
||||
}
|
||||
|
||||
@OutputFile
|
||||
public abstract RegularFileProperty getNextReleaseFile();
|
||||
|
||||
public RepositoryRef getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
public void repository(Action<RepositoryRef> 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;
|
||||
this.milestones = new GitHubMilestoneApi(gitHubAccessToken);
|
||||
}
|
||||
|
||||
private Yaml getYaml() {
|
||||
Representer representer = new Representer();
|
||||
representer.addClassTag(NextVersionYml.class, Tag.MAP);
|
||||
DumperOptions ymlOptions = new DumperOptions();
|
||||
ymlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
return new Yaml(representer, ymlOptions);
|
||||
}
|
||||
|
||||
}
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.gradle.github.milestones;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.work.DisableCachingByDefault;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
|
||||
@DisableCachingByDefault(because = "the due date needs to be checked every time in case it changes")
|
||||
public abstract class GitHubMilestoneNextVersionDueTodayTask extends DefaultTask {
|
||||
|
||||
@Input
|
||||
private RepositoryRef repository = new RepositoryRef();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
private String gitHubAccessToken;
|
||||
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getNextVersionFile();
|
||||
|
||||
@OutputFile
|
||||
public abstract RegularFileProperty getIsDueTodayFile();
|
||||
|
||||
private GitHubMilestoneApi milestones = new GitHubMilestoneApi();
|
||||
|
||||
@TaskAction
|
||||
public void checkReleaseDueToday() throws IOException {
|
||||
File nextVersionFile = getNextVersionFile().getAsFile().get();
|
||||
Yaml yaml = new Yaml(new Constructor(NextVersionYml.class));
|
||||
NextVersionYml nextVersionYml = yaml.load(new FileInputStream(nextVersionFile));
|
||||
String nextVersion = nextVersionYml.getVersion();
|
||||
if (nextVersion == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not find version property in provided file " + nextVersionFile.getName());
|
||||
}
|
||||
boolean milestoneDueToday = this.milestones.isMilestoneDueToday(this.repository, nextVersion);
|
||||
Path isDueTodayPath = getIsDueTodayFile().getAsFile().get().toPath();
|
||||
Files.writeString(isDueTodayPath, String.valueOf(milestoneDueToday));
|
||||
if (milestoneDueToday) {
|
||||
System.out.println("The milestone with the title " + nextVersion + " in the repository " + this.repository
|
||||
+ " is due today");
|
||||
}
|
||||
else {
|
||||
System.out.println("The milestone with the title " + nextVersion + " in the repository "
|
||||
+ this.repository + " is not due yet");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public RepositoryRef getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
public void repository(Action<RepositoryRef> 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;
|
||||
this.milestones = new GitHubMilestoneApi(gitHubAccessToken);
|
||||
}
|
||||
|
||||
}
|
||||
+11
-43
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,55 +16,23 @@
|
||||
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
|
||||
public class GitHubMilestonePlugin implements Plugin<Project> {
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
TaskProvider<GitHubMilestoneNextReleaseTask> nextReleaseMilestoneTask = project.getTasks().register("gitHubNextReleaseMilestone", GitHubMilestoneNextReleaseTask.class, (gitHubMilestoneNextReleaseTask) -> {
|
||||
gitHubMilestoneNextReleaseTask.doNotTrackState("API call to GitHub needs to check for new milestones every time");
|
||||
gitHubMilestoneNextReleaseTask.setGroup("Release");
|
||||
gitHubMilestoneNextReleaseTask.setDescription("Calculates the next release version based on the current version and outputs it to a yaml file");
|
||||
gitHubMilestoneNextReleaseTask.getNextReleaseFile()
|
||||
.fileProvider(project.provider(() -> project.file("next-release.yml")));
|
||||
if (project.hasProperty("gitHubAccessToken")) {
|
||||
gitHubMilestoneNextReleaseTask
|
||||
.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
|
||||
project.getTasks().register("gitHubCheckMilestoneHasNoOpenIssues", GitHubMilestoneHasNoOpenIssuesTask.class, new Action<GitHubMilestoneHasNoOpenIssuesTask>() {
|
||||
@Override
|
||||
public void execute(GitHubMilestoneHasNoOpenIssuesTask githubCheckMilestoneHasNoOpenIssues) {
|
||||
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")) {
|
||||
githubCheckMilestoneHasNoOpenIssues.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
|
||||
}
|
||||
}
|
||||
});
|
||||
project.getTasks().register("gitHubCheckMilestoneHasNoOpenIssues", GitHubMilestoneHasNoOpenIssuesTask.class, (githubCheckMilestoneHasNoOpenIssues) -> {
|
||||
githubCheckMilestoneHasNoOpenIssues.setGroup("Release");
|
||||
githubCheckMilestoneHasNoOpenIssues.setDescription("Checks if there are any open issues for the specified repository and milestone");
|
||||
githubCheckMilestoneHasNoOpenIssues.getIsOpenIssuesFile().value(project.getLayout().getBuildDirectory().file("github/milestones/is-open-issues"));
|
||||
githubCheckMilestoneHasNoOpenIssues.setMilestoneTitle((String) project.findProperty("nextVersion"));
|
||||
if (!project.hasProperty("nextVersion")) {
|
||||
githubCheckMilestoneHasNoOpenIssues.getNextVersionFile().convention(
|
||||
nextReleaseMilestoneTask.flatMap(GitHubMilestoneNextReleaseTask::getNextReleaseFile));
|
||||
}
|
||||
if (project.hasProperty("gitHubAccessToken")) {
|
||||
githubCheckMilestoneHasNoOpenIssues.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
|
||||
}
|
||||
});
|
||||
project.getTasks().register("gitHubCheckNextVersionDueToday", GitHubMilestoneNextVersionDueTodayTask.class, (gitHubMilestoneNextVersionDueTodayTask) -> {
|
||||
gitHubMilestoneNextVersionDueTodayTask.setGroup("Release");
|
||||
gitHubMilestoneNextVersionDueTodayTask.setDescription("Checks if the next release version is due today or past due, will fail if the next version is not due yet");
|
||||
gitHubMilestoneNextVersionDueTodayTask.getIsDueTodayFile().value(project.getLayout().getBuildDirectory().file("github/milestones/is-due-today"));
|
||||
gitHubMilestoneNextVersionDueTodayTask.getNextVersionFile().convention(
|
||||
nextReleaseMilestoneTask.flatMap(GitHubMilestoneNextReleaseTask::getNextReleaseFile));
|
||||
if (project.hasProperty("gitHubAccessToken")) {
|
||||
gitHubMilestoneNextVersionDueTodayTask
|
||||
.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
|
||||
}
|
||||
});
|
||||
project.getTasks().register("scheduleNextRelease", ScheduleNextReleaseTask.class, (scheduleNextRelease) -> {
|
||||
scheduleNextRelease.doNotTrackState("API call to GitHub needs to check for new milestones every time");
|
||||
scheduleNextRelease.setGroup("Release");
|
||||
scheduleNextRelease.setDescription("Schedule the next release (even months only) or release train (series of milestones starting in January or July) based on the current version");
|
||||
|
||||
scheduleNextRelease.setVersion((String) project.findProperty("nextVersion"));
|
||||
scheduleNextRelease.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
class LocalDateAdapter extends TypeAdapter<LocalDate> {
|
||||
@Override
|
||||
public void write(JsonWriter jsonWriter, LocalDate localDate) throws IOException {
|
||||
jsonWriter.value(localDate.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate read(JsonReader jsonReader) throws IOException {
|
||||
return LocalDate.parse(jsonReader.nextString());
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
class LocalDateTimeAdapter extends TypeAdapter<LocalDateTime> {
|
||||
@Override
|
||||
public void write(JsonWriter jsonWriter, LocalDateTime localDateTime) throws IOException {
|
||||
jsonWriter.value(localDateTime.atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime read(JsonReader jsonReader) throws IOException {
|
||||
return LocalDateTime.parse(jsonReader.nextString(), DateTimeFormatter.ISO_ZONED_DATE_TIME);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,9 @@
|
||||
/*
|
||||
* Copyright 2019-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.gradle.github.milestones;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class Milestone {
|
||||
private String title;
|
||||
|
||||
private Long number;
|
||||
|
||||
@SerializedName("due_on")
|
||||
private LocalDateTime dueOn;
|
||||
private long number;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
@@ -39,28 +13,19 @@ public class Milestone {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Long getNumber() {
|
||||
public long getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(Long number) {
|
||||
public void setNumber(long number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public LocalDateTime getDueOn() {
|
||||
return dueOn;
|
||||
}
|
||||
|
||||
public void setDueOn(LocalDateTime dueOn) {
|
||||
this.dueOn = dueOn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Milestone{" +
|
||||
"title='" + title + '\'' +
|
||||
", number='" + number + '\'' +
|
||||
", dueOn='" + dueOn + '\'' +
|
||||
", number=" + number +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.gradle.github.milestones;
|
||||
|
||||
public class NextVersionYml {
|
||||
private String version;
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
+4
-9
@@ -1,16 +1,10 @@
|
||||
package org.springframework.gradle.github;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class RepositoryRef implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7151218536746822797L;
|
||||
|
||||
package org.springframework.gradle.github.milestones;
|
||||
public class RepositoryRef {
|
||||
private String owner;
|
||||
|
||||
private String name;
|
||||
|
||||
public RepositoryRef() {
|
||||
RepositoryRef() {
|
||||
}
|
||||
|
||||
public RepositoryRef(String owner, String name) {
|
||||
@@ -68,3 +62,4 @@ public class RepositoryRef implements Serializable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class ScheduleNextReleaseTask extends DefaultTask {
|
||||
@Input
|
||||
private RepositoryRef repository = new RepositoryRef();
|
||||
|
||||
@Input
|
||||
private String gitHubAccessToken;
|
||||
|
||||
@Input
|
||||
private String version;
|
||||
|
||||
@Input
|
||||
private Integer weekOfMonth;
|
||||
|
||||
@Input
|
||||
private Integer dayOfWeek;
|
||||
|
||||
@TaskAction
|
||||
public void scheduleNextRelease() {
|
||||
GitHubMilestoneApi gitHubMilestoneApi = new GitHubMilestoneApi(this.gitHubAccessToken);
|
||||
String nextReleaseMilestone = gitHubMilestoneApi.getNextReleaseMilestone(this.repository, this.version);
|
||||
|
||||
// If the next release contains a dash (e.g. 5.6.0-RC1), it is already scheduled
|
||||
if (nextReleaseMilestone.contains("-")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if a scheduled GA version already exists
|
||||
boolean hasExistingMilestone = gitHubMilestoneApi.getMilestones(this.repository).stream()
|
||||
.anyMatch(milestone -> nextReleaseMilestone.equals(milestone.getTitle()));
|
||||
if (hasExistingMilestone) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Next milestone is either a patch version or minor version
|
||||
// Note: Major versions will be handled like minor and get a release
|
||||
// train which can be manually updated to match the desired schedule.
|
||||
if (nextReleaseMilestone.endsWith(".0")) {
|
||||
// Create M1, M2, M3, RC1 and GA milestones for release train
|
||||
getReleaseTrain(nextReleaseMilestone).getTrainDates().forEach((milestoneTitle, dueOn) -> {
|
||||
Milestone milestone = new Milestone();
|
||||
milestone.setTitle(milestoneTitle);
|
||||
// Note: GitHub seems to store full date/time as UTC then displays
|
||||
// as a date (no time) in your timezone, which means the date will
|
||||
// not always be the same date as we intend.
|
||||
// Using 12pm/noon UTC allows GitHub to schedule and display the
|
||||
// correct date.
|
||||
milestone.setDueOn(dueOn.atTime(LocalTime.NOON));
|
||||
gitHubMilestoneApi.createMilestone(this.repository, milestone);
|
||||
});
|
||||
} else {
|
||||
// Create GA milestone for patch release on the next even month
|
||||
LocalDate startDate = LocalDate.now();
|
||||
LocalDate dueOn = getReleaseTrain(nextReleaseMilestone).getNextReleaseDate(startDate);
|
||||
Milestone milestone = new Milestone();
|
||||
milestone.setTitle(nextReleaseMilestone);
|
||||
milestone.setDueOn(dueOn.atTime(LocalTime.NOON));
|
||||
gitHubMilestoneApi.createMilestone(this.repository, milestone);
|
||||
}
|
||||
}
|
||||
|
||||
private SpringReleaseTrain getReleaseTrain(String nextReleaseMilestone) {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.nextTrain()
|
||||
.version(nextReleaseMilestone)
|
||||
.weekOfMonth(this.weekOfMonth)
|
||||
.dayOfWeek(this.dayOfWeek)
|
||||
.build();
|
||||
|
||||
return new SpringReleaseTrain(releaseTrainSpec);
|
||||
}
|
||||
|
||||
public RepositoryRef getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
public void repository(Action<RepositoryRef> repository) {
|
||||
repository.execute(this.repository);
|
||||
}
|
||||
|
||||
public void setRepository(RepositoryRef repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public String getGitHubAccessToken() {
|
||||
return this.gitHubAccessToken;
|
||||
}
|
||||
|
||||
public void setGitHubAccessToken(String gitHubAccessToken) {
|
||||
this.gitHubAccessToken = gitHubAccessToken;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Integer getWeekOfMonth() {
|
||||
return weekOfMonth;
|
||||
}
|
||||
|
||||
public void setWeekOfMonth(Integer weekOfMonth) {
|
||||
this.weekOfMonth = weekOfMonth;
|
||||
}
|
||||
|
||||
public Integer getDayOfWeek() {
|
||||
return dayOfWeek;
|
||||
}
|
||||
|
||||
public void setDayOfWeek(Integer dayOfWeek) {
|
||||
this.dayOfWeek = dayOfWeek;
|
||||
}
|
||||
}
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.time.Year;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Spring release train generator based on rules contained in a specification.
|
||||
* <p>
|
||||
* The rules are:
|
||||
* <ol>
|
||||
* <li>Train 1 (January-May) or 2 (July-November)</li>
|
||||
* <li>Version number (e.g. 0.1.2, 1.0.0, etc.)</li>
|
||||
* <li>Week of month (1st, 2nd, 3rd, 4th)</li>
|
||||
* <li>Day of week (Monday-Friday)</li>
|
||||
* <li>Year (e.g. 2020, 2021, etc.)</li>
|
||||
* </ol>
|
||||
*
|
||||
* The release train generated will contain M1, M2, M3, RC1 and GA versions
|
||||
* mapped to their respective dates in the train.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public final class SpringReleaseTrain {
|
||||
private final SpringReleaseTrainSpec releaseTrainSpec;
|
||||
|
||||
public SpringReleaseTrain(SpringReleaseTrainSpec releaseTrainSpec) {
|
||||
this.releaseTrainSpec = releaseTrainSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate release train dates based on the release train specification.
|
||||
*
|
||||
* @return A mapping of release milestones to scheduled release dates
|
||||
*/
|
||||
public Map<String, LocalDate> getTrainDates() {
|
||||
Map<String, LocalDate> releaseDates = new LinkedHashMap<>();
|
||||
switch (this.releaseTrainSpec.getTrain()) {
|
||||
case ONE:
|
||||
addTrainDate(releaseDates, "M1", Month.JANUARY);
|
||||
addTrainDate(releaseDates, "M2", Month.FEBRUARY);
|
||||
addTrainDate(releaseDates, "M3", Month.MARCH);
|
||||
addTrainDate(releaseDates, "RC1", Month.APRIL);
|
||||
addTrainDate(releaseDates, null, Month.MAY);
|
||||
break;
|
||||
case TWO:
|
||||
addTrainDate(releaseDates, "M1", Month.JULY);
|
||||
addTrainDate(releaseDates, "M2", Month.AUGUST);
|
||||
addTrainDate(releaseDates, "M3", Month.SEPTEMBER);
|
||||
addTrainDate(releaseDates, "RC1", Month.OCTOBER);
|
||||
addTrainDate(releaseDates, null, Month.NOVEMBER);
|
||||
break;
|
||||
}
|
||||
|
||||
return releaseDates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given date matches the due date of given version.
|
||||
*
|
||||
* @param version The version number (e.g. 5.6.0-M1, 5.6.0, etc.)
|
||||
* @param expectedDate The expected date
|
||||
* @return true if the given date matches the due date of the given version, false otherwise
|
||||
*/
|
||||
public boolean isTrainDate(String version, LocalDate expectedDate) {
|
||||
return expectedDate.isEqual(getTrainDates().get(version));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the next release date following the given date.
|
||||
* <p>
|
||||
* The next release date is always on an even month so that a patch release
|
||||
* is the month after the GA version of a release train. This method does
|
||||
* not consider the year of the release train, only the given start date.
|
||||
*
|
||||
* @param startDate The start date
|
||||
* @return The next release date following the given date
|
||||
*/
|
||||
public LocalDate getNextReleaseDate(LocalDate startDate) {
|
||||
LocalDate trainDate;
|
||||
LocalDate currentDate = startDate;
|
||||
do {
|
||||
trainDate = calculateReleaseDate(
|
||||
Year.of(currentDate.getYear()),
|
||||
currentDate.getMonth(),
|
||||
this.releaseTrainSpec.getDayOfWeek().getDayOfWeek(),
|
||||
this.releaseTrainSpec.getWeekOfMonth().getDayOffset()
|
||||
);
|
||||
currentDate = currentDate.plusMonths(1);
|
||||
} while (!trainDate.isAfter(startDate) || trainDate.getMonthValue() % 2 != 0);
|
||||
|
||||
return trainDate;
|
||||
}
|
||||
|
||||
private void addTrainDate(Map<String, LocalDate> releaseDates, String milestone, Month month) {
|
||||
LocalDate releaseDate = calculateReleaseDate(
|
||||
this.releaseTrainSpec.getYear(),
|
||||
month,
|
||||
this.releaseTrainSpec.getDayOfWeek().getDayOfWeek(),
|
||||
this.releaseTrainSpec.getWeekOfMonth().getDayOffset()
|
||||
);
|
||||
String suffix = (milestone == null) ? "" : "-" + milestone;
|
||||
releaseDates.put(this.releaseTrainSpec.getVersion() + suffix, releaseDate);
|
||||
}
|
||||
|
||||
private static LocalDate calculateReleaseDate(Year year, Month month, DayOfWeek dayOfWeek, int dayOffset) {
|
||||
TemporalAdjuster nextMonday = TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY);
|
||||
TemporalAdjuster nextDayOfWeek = TemporalAdjusters.nextOrSame(dayOfWeek);
|
||||
|
||||
LocalDate firstDayOfMonth = year.atMonth(month).atDay(1);
|
||||
LocalDate firstMondayOfMonth = firstDayOfMonth.with(nextMonday);
|
||||
|
||||
return firstMondayOfMonth.with(nextDayOfWeek).plusDays(dayOffset);
|
||||
}
|
||||
}
|
||||
-205
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.time.Year;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A specification for a release train.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
* @see SpringReleaseTrain
|
||||
*/
|
||||
public final class SpringReleaseTrainSpec {
|
||||
private final Train train;
|
||||
private final String version;
|
||||
private final WeekOfMonth weekOfMonth;
|
||||
private final DayOfWeek dayOfWeek;
|
||||
private final Year year;
|
||||
|
||||
public SpringReleaseTrainSpec(Train train, String version, WeekOfMonth weekOfMonth, DayOfWeek dayOfWeek, Year year) {
|
||||
this.train = train;
|
||||
this.version = version;
|
||||
this.weekOfMonth = weekOfMonth;
|
||||
this.dayOfWeek = dayOfWeek;
|
||||
this.year = year;
|
||||
}
|
||||
|
||||
public Train getTrain() {
|
||||
return train;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public WeekOfMonth getWeekOfMonth() {
|
||||
return weekOfMonth;
|
||||
}
|
||||
|
||||
public DayOfWeek getDayOfWeek() {
|
||||
return dayOfWeek;
|
||||
}
|
||||
|
||||
public Year getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public enum WeekOfMonth {
|
||||
FIRST(0), SECOND(7), THIRD(14), FOURTH(21);
|
||||
|
||||
private final int dayOffset;
|
||||
|
||||
WeekOfMonth(int dayOffset) {
|
||||
this.dayOffset = dayOffset;
|
||||
}
|
||||
|
||||
public int getDayOffset() {
|
||||
return dayOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DayOfWeek {
|
||||
MONDAY(java.time.DayOfWeek.MONDAY),
|
||||
TUESDAY(java.time.DayOfWeek.TUESDAY),
|
||||
WEDNESDAY(java.time.DayOfWeek.WEDNESDAY),
|
||||
THURSDAY(java.time.DayOfWeek.THURSDAY),
|
||||
FRIDAY(java.time.DayOfWeek.FRIDAY);
|
||||
|
||||
private final java.time.DayOfWeek dayOfWeek;
|
||||
|
||||
DayOfWeek(java.time.DayOfWeek dayOfWeek) {
|
||||
this.dayOfWeek = dayOfWeek;
|
||||
}
|
||||
|
||||
public java.time.DayOfWeek getDayOfWeek() {
|
||||
return dayOfWeek;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Train {
|
||||
ONE, TWO
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Train train;
|
||||
private String version;
|
||||
private WeekOfMonth weekOfMonth;
|
||||
private DayOfWeek dayOfWeek;
|
||||
private Year year;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
public Builder train(int train) {
|
||||
switch (train) {
|
||||
case 1: this.train = Train.ONE; break;
|
||||
case 2: this.train = Train.TWO; break;
|
||||
default: throw new IllegalArgumentException("Invalid train: " + train);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder train(Train train) {
|
||||
this.train = train;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder nextTrain() {
|
||||
// Search for next train starting with this month
|
||||
return nextTrain(LocalDate.now().withDayOfMonth(1));
|
||||
}
|
||||
|
||||
public Builder nextTrain(LocalDate startDate) {
|
||||
Train nextTrain = null;
|
||||
|
||||
// Search for next train from a given start date
|
||||
LocalDate currentDate = startDate;
|
||||
while (nextTrain == null) {
|
||||
if (currentDate.getMonth() == Month.JANUARY) {
|
||||
nextTrain = Train.ONE;
|
||||
} else if (currentDate.getMonth() == Month.JULY) {
|
||||
nextTrain = Train.TWO;
|
||||
}
|
||||
|
||||
currentDate = currentDate.plusMonths(1);
|
||||
}
|
||||
|
||||
return train(nextTrain).year(currentDate.getYear());
|
||||
}
|
||||
|
||||
public Builder version(String version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder weekOfMonth(int weekOfMonth) {
|
||||
switch (weekOfMonth) {
|
||||
case 1: this.weekOfMonth = WeekOfMonth.FIRST; break;
|
||||
case 2: this.weekOfMonth = WeekOfMonth.SECOND; break;
|
||||
case 3: this.weekOfMonth = WeekOfMonth.THIRD; break;
|
||||
case 4: this.weekOfMonth = WeekOfMonth.FOURTH; break;
|
||||
default: throw new IllegalArgumentException("Invalid weekOfMonth: " + weekOfMonth);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder weekOfMonth(WeekOfMonth weekOfMonth) {
|
||||
this.weekOfMonth = weekOfMonth;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder dayOfWeek(int dayOfWeek) {
|
||||
switch (dayOfWeek) {
|
||||
case 1: this.dayOfWeek = DayOfWeek.MONDAY; break;
|
||||
case 2: this.dayOfWeek = DayOfWeek.TUESDAY; break;
|
||||
case 3: this.dayOfWeek = DayOfWeek.WEDNESDAY; break;
|
||||
case 4: this.dayOfWeek = DayOfWeek.THURSDAY; break;
|
||||
case 5: this.dayOfWeek = DayOfWeek.FRIDAY; break;
|
||||
default: throw new IllegalArgumentException("Invalid dayOfWeek: " + dayOfWeek);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder dayOfWeek(DayOfWeek dayOfWeek) {
|
||||
this.dayOfWeek = dayOfWeek;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder year(int year) {
|
||||
this.year = Year.of(year);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SpringReleaseTrainSpec build() {
|
||||
Assert.notNull(train, "train cannot be null");
|
||||
Assert.notNull(version, "version cannot be null");
|
||||
Assert.notNull(weekOfMonth, "weekOfMonth cannot be null");
|
||||
Assert.notNull(dayOfWeek, "dayOfWeek cannot be null");
|
||||
Assert.notNull(year, "year cannot be null");
|
||||
return new SpringReleaseTrainSpec(train, version, weekOfMonth, dayOfWeek, year);
|
||||
}
|
||||
}
|
||||
}
|
||||
-130
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* 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<RepositoryRef> 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;
|
||||
}
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.github.release;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class DispatchGitHubWorkflowTask extends DefaultTask {
|
||||
@Input
|
||||
private RepositoryRef repository = new RepositoryRef();
|
||||
|
||||
@Input
|
||||
private String gitHubAccessToken;
|
||||
|
||||
@Input
|
||||
private String branch;
|
||||
|
||||
@Input
|
||||
private String workflowId;
|
||||
|
||||
@TaskAction
|
||||
public void dispatchGitHubWorkflow() {
|
||||
GitHubActionsApi gitHubActionsApi = new GitHubActionsApi(this.gitHubAccessToken);
|
||||
WorkflowDispatch workflowDispatch = new WorkflowDispatch(this.branch, null);
|
||||
gitHubActionsApi.dispatchWorkflow(this.repository, this.workflowId, workflowDispatch);
|
||||
}
|
||||
|
||||
public RepositoryRef getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
public void repository(Action<RepositoryRef> 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 getBranch() {
|
||||
return branch;
|
||||
}
|
||||
|
||||
public void setBranch(String branch) {
|
||||
this.branch = branch;
|
||||
}
|
||||
|
||||
public String getWorkflowId() {
|
||||
return workflowId;
|
||||
}
|
||||
|
||||
public void setWorkflowId(String workflowId) {
|
||||
this.workflowId = workflowId;
|
||||
}
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.github.release;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
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 Actions.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class GitHubActionsApi {
|
||||
private String baseUrl = "https://api.github.com";
|
||||
|
||||
private final OkHttpClient client;
|
||||
|
||||
private final Gson gson = new GsonBuilder().create();
|
||||
|
||||
public GitHubActionsApi() {
|
||||
this.client = new OkHttpClient.Builder().build();
|
||||
}
|
||||
|
||||
public GitHubActionsApi(String gitHubToken) {
|
||||
this.client = new OkHttpClient.Builder()
|
||||
.addInterceptor(new AuthorizationInterceptor(gitHubToken))
|
||||
.build();
|
||||
}
|
||||
|
||||
public void setBaseUrl(String baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a workflow dispatch event.
|
||||
*
|
||||
* @param repository The repository owner/name
|
||||
* @param workflowId The ID of the workflow or the name of the workflow file name
|
||||
* @param workflowDispatch The workflow dispatch containing a ref (branch) and optional inputs
|
||||
*/
|
||||
public void dispatchWorkflow(RepositoryRef repository, String workflowId, WorkflowDispatch workflowDispatch) {
|
||||
String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/actions/workflows/" + workflowId + "/dispatches";
|
||||
String json = this.gson.toJson(workflowDispatch);
|
||||
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
|
||||
Request request = new Request.Builder().url(url).post(body).build();
|
||||
try {
|
||||
Response response = this.client.newCall(request).execute();
|
||||
if (!response.isSuccessful()) {
|
||||
throw new RuntimeException(String.format("Could not create workflow dispatch %s for repository %s/%s. Got response %s",
|
||||
workflowId, repository.getOwner(), repository.getName(), response));
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(String.format("Could not create workflow dispatch %s for repository %s/%s",
|
||||
workflowId, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class GitHubReleasePlugin implements Plugin<Project> {
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getTasks().register("createGitHubRelease", CreateGitHubReleaseTask.class, (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=...");
|
||||
}
|
||||
});
|
||||
|
||||
project.getTasks().register("dispatchGitHubWorkflow", DispatchGitHubWorkflowTask.class, (dispatchGitHubWorkflow) -> {
|
||||
dispatchGitHubWorkflow.setGroup("Release");
|
||||
dispatchGitHubWorkflow.setDescription("Create a workflow_dispatch event on a given branch");
|
||||
|
||||
dispatchGitHubWorkflow.setBranch((String) project.findProperty("branch"));
|
||||
dispatchGitHubWorkflow.setWorkflowId((String) project.findProperty("workflowId"));
|
||||
dispatchGitHubWorkflow.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.github.release;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class WorkflowDispatch {
|
||||
private String ref;
|
||||
private Map<String, Object> inputs;
|
||||
|
||||
public WorkflowDispatch() {
|
||||
}
|
||||
|
||||
public WorkflowDispatch(String ref, Map<String, Object> inputs) {
|
||||
this.ref = ref;
|
||||
this.inputs = inputs;
|
||||
}
|
||||
|
||||
public String getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public void setRef(String ref) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
public Map<String, Object> getInputs() {
|
||||
return inputs;
|
||||
}
|
||||
|
||||
public void setInputs(Map<String, Object> inputs) {
|
||||
this.inputs = inputs;
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.convention.versions;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Scanner;
|
||||
|
||||
class CommandLineUtils {
|
||||
static void runCommand(File dir, String... args) {
|
||||
try {
|
||||
Process process = new ProcessBuilder()
|
||||
.directory(dir)
|
||||
.command(args)
|
||||
.start();
|
||||
writeLinesTo(process.getInputStream(), System.out);
|
||||
writeLinesTo(process.getErrorStream(), System.out);
|
||||
if (process.waitFor() != 0) {
|
||||
new RuntimeException("Failed to run " + Arrays.toString(args));
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new RuntimeException("Failed to run " + Arrays.toString(args), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeLinesTo(InputStream input, PrintStream out) {
|
||||
Scanner scanner = new Scanner(input);
|
||||
while(scanner.hasNextLine()) {
|
||||
out.println(scanner.nextLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.convention.versions;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.function.Function;
|
||||
|
||||
class FileUtils {
|
||||
static void replaceFileText(File file, Function<String, String> replaceText) {
|
||||
String buildFileText = readString(file);
|
||||
String updatedBuildFileText = replaceText.apply(buildFileText);
|
||||
writeString(file, updatedBuildFileText);
|
||||
}
|
||||
|
||||
static String readString(File file) {
|
||||
try {
|
||||
byte[] bytes = Files.readAllBytes(file.toPath());
|
||||
return new String(bytes);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeString(File file, String text) {
|
||||
try {
|
||||
Files.write(file.toPath(), text.getBytes());
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-5
@@ -33,8 +33,13 @@ import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.file.Files;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -163,7 +168,7 @@ public class UpdateDependenciesPlugin implements Plugin<Project> {
|
||||
Integer issueNumber = gitHubApi.createIssue(createIssueResult.getRepositoryId(), title, createIssueResult.getLabelIds(), createIssueResult.getMilestoneId(), createIssueResult.getAssigneeId()).delayElement(Duration.ofSeconds(1)).block();
|
||||
commitMessage += "\n\nCloses gh-" + issueNumber;
|
||||
}
|
||||
CommandLineUtils.runCommand(rootDir, "git", "commit", "-am", commitMessage);
|
||||
runCommand(rootDir, "git", "commit", "-am", commitMessage);
|
||||
}
|
||||
|
||||
private Mono<GitHubApi.FindCreateIssueResult> createIssueResultMono(UpdateDependenciesExtension updateDependenciesExtension) {
|
||||
@@ -182,7 +187,7 @@ public class UpdateDependenciesPlugin implements Plugin<Project> {
|
||||
if (current.compareTo(running) > 0) {
|
||||
String title = "Update Gradle to " + current.getVersion();
|
||||
System.out.println(title);
|
||||
CommandLineUtils.runCommand(project.getRootDir(), "./gradlew", "wrapper", "--gradle-version", current.getVersion(), "--no-daemon");
|
||||
runCommand(project.getRootDir(), "./gradlew", "wrapper", "--gradle-version", current.getVersion(), "--no-daemon");
|
||||
afterGroup(updateDependenciesSettings, project.getRootDir(), title, createIssueResultMono(updateDependenciesSettings));
|
||||
}
|
||||
}
|
||||
@@ -199,6 +204,30 @@ public class UpdateDependenciesPlugin implements Plugin<Project> {
|
||||
};
|
||||
}
|
||||
|
||||
static void runCommand(File dir, String... args) {
|
||||
try {
|
||||
Process process = new ProcessBuilder()
|
||||
.directory(dir)
|
||||
.command(args)
|
||||
.start();
|
||||
writeLinesTo(process.getInputStream(), System.out);
|
||||
writeLinesTo(process.getErrorStream(), System.out);
|
||||
if (process.waitFor() != 0) {
|
||||
new RuntimeException("Failed to run " + Arrays.toString(args));
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new RuntimeException("Failed to run " + Arrays.toString(args), e);
|
||||
}
|
||||
}
|
||||
|
||||
static void writeLinesTo(InputStream input, PrintStream out) {
|
||||
Scanner scanner = new Scanner(input);
|
||||
while(scanner.hasNextLine()) {
|
||||
out.println(scanner.nextLine());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Action<ComponentSelectionWithCurrent> excludeWithRegex(String regex, String reason) {
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
return (selection) -> {
|
||||
@@ -213,17 +242,40 @@ public class UpdateDependenciesPlugin implements Plugin<Project> {
|
||||
String ga = dependency.getGroup() + ":" + dependency.getName() + ":";
|
||||
String originalDependency = ga + dependency.getVersion();
|
||||
String replacementDependency = ga + updatedVersion(dependency);
|
||||
FileUtils.replaceFileText(buildFile, buildFileText -> buildFileText.replace(originalDependency, replacementDependency));
|
||||
replaceFileText(buildFile, buildFileText -> buildFileText.replace(originalDependency, replacementDependency));
|
||||
}
|
||||
|
||||
static void replaceFileText(File file, Function<String, String> replaceText) {
|
||||
String buildFileText = readString(file);
|
||||
String updatedBuildFileText = replaceText.apply(buildFileText);
|
||||
writeString(file, updatedBuildFileText);
|
||||
}
|
||||
|
||||
private static String readString(File file) {
|
||||
try {
|
||||
byte[] bytes = Files.readAllBytes(file.toPath());
|
||||
return new String(bytes);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeString(File file, String text) {
|
||||
try {
|
||||
Files.write(file.toPath(), text.getBytes());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void updateDependencyWithVersionVariable(File scanFile, File gradlePropertiesFile, DependencyOutdated dependency) {
|
||||
if (!gradlePropertiesFile.exists()) {
|
||||
return;
|
||||
}
|
||||
FileUtils.replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> {
|
||||
replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> {
|
||||
String ga = dependency.getGroup() + ":" + dependency.getName() + ":";
|
||||
Pattern pattern = Pattern.compile("\"" + ga + "\\$\\{?([^'\"]+?)\\}?\"");
|
||||
String buildFileText = FileUtils.readString(scanFile);
|
||||
String buildFileText = readString(scanFile);
|
||||
Matcher matcher = pattern.matcher(buildFileText);
|
||||
while (matcher.find()) {
|
||||
String versionVariable = matcher.group(1);
|
||||
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.convention.versions;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
public class UpdateProjectVersionPlugin implements Plugin<Project> {
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getTasks().register("updateProjectVersion", UpdateProjectVersionTask.class, new Action<UpdateProjectVersionTask>() {
|
||||
@Override
|
||||
public void execute(UpdateProjectVersionTask updateProjectVersionTask) {
|
||||
updateProjectVersionTask.setGroup("Release");
|
||||
updateProjectVersionTask.setDescription("Updates the project version to the next release in gradle.properties");
|
||||
updateProjectVersionTask.dependsOn("gitHubNextReleaseMilestone");
|
||||
updateProjectVersionTask.getNextVersionFile().fileProvider(project.provider(() -> project.file("next-release.yml")));
|
||||
}
|
||||
});
|
||||
project.getTasks().register("updateToSnapshotVersion", UpdateToSnapshotVersionTask.class, new Action<UpdateToSnapshotVersionTask>() {
|
||||
@Override
|
||||
public void execute(UpdateToSnapshotVersionTask updateToSnapshotVersionTask) {
|
||||
updateToSnapshotVersionTask.setGroup("Release");
|
||||
updateToSnapshotVersionTask.setDescription(
|
||||
"Updates the project version to the next snapshot in gradle.properties");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.convention.versions;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import org.springframework.gradle.github.milestones.NextVersionYml;
|
||||
|
||||
public abstract class UpdateProjectVersionTask extends DefaultTask {
|
||||
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getNextVersionFile();
|
||||
|
||||
@TaskAction
|
||||
public void checkReleaseDueToday() throws FileNotFoundException {
|
||||
File nextVersionFile = getNextVersionFile().getAsFile().get();
|
||||
Yaml yaml = new Yaml(new Constructor(NextVersionYml.class));
|
||||
NextVersionYml nextVersionYml = yaml.load(new FileInputStream(nextVersionFile));
|
||||
String nextVersion = nextVersionYml.getVersion();
|
||||
if (nextVersion == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not find version property in provided file " + nextVersionFile.getName());
|
||||
}
|
||||
String currentVersion = getProject().getVersion().toString();
|
||||
File gradlePropertiesFile = getProject().getRootProject().file(Project.GRADLE_PROPERTIES);
|
||||
if (!gradlePropertiesFile.exists()) {
|
||||
return;
|
||||
}
|
||||
System.out.println("Updating the project version in " + Project.GRADLE_PROPERTIES + " from " + currentVersion
|
||||
+ " to " + nextVersion);
|
||||
FileUtils.replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> {
|
||||
gradlePropertiesText = gradlePropertiesText.replace("version=" + currentVersion, "version=" + nextVersion);
|
||||
return gradlePropertiesText;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-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.convention.versions;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class UpdateToSnapshotVersionTask extends DefaultTask {
|
||||
|
||||
private static final String RELEASE_VERSION_PATTERN = "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-M\\d+|-RC\\d+)?$";
|
||||
|
||||
@TaskAction
|
||||
public void updateToSnapshotVersion() {
|
||||
String currentVersion = getProject().getVersion().toString();
|
||||
File gradlePropertiesFile = getProject().getRootProject().file(Project.GRADLE_PROPERTIES);
|
||||
if (!gradlePropertiesFile.exists()) {
|
||||
return;
|
||||
}
|
||||
String nextVersion = calculateNextSnapshotVersion(currentVersion);
|
||||
System.out.println("Updating the project version in " + Project.GRADLE_PROPERTIES + " from " + currentVersion
|
||||
+ " to " + nextVersion);
|
||||
FileUtils.replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> {
|
||||
gradlePropertiesText = gradlePropertiesText.replace("version=" + currentVersion, "version=" + nextVersion);
|
||||
return gradlePropertiesText;
|
||||
});
|
||||
}
|
||||
|
||||
private String calculateNextSnapshotVersion(String currentVersion) {
|
||||
Pattern releaseVersionPattern = Pattern.compile(RELEASE_VERSION_PATTERN);
|
||||
Matcher releaseVersion = releaseVersionPattern.matcher(currentVersion);
|
||||
|
||||
if (releaseVersion.find()) {
|
||||
String majorSegment = releaseVersion.group(1);
|
||||
String minorSegment = releaseVersion.group(2);
|
||||
String patchSegment = releaseVersion.group(3);
|
||||
String modifier = releaseVersion.group(4);
|
||||
if (modifier == null) {
|
||||
patchSegment = String.valueOf(Integer.parseInt(patchSegment) + 1);
|
||||
}
|
||||
System.out.println("modifier = " + modifier);
|
||||
return String.format("%s.%s.%s-SNAPSHOT", majorSegment, minorSegment, patchSegment);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Cannot calculate next snapshot version because the current project version does not conform to the expected format");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -164,18 +164,14 @@ public class S101Configurer {
|
||||
String source = "https://structure101.com/binaries/v6";
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
HtmlPage page = webClient.getPage(source);
|
||||
Matcher matcher = null;
|
||||
for (HtmlAnchor anchor : page.getAnchors()) {
|
||||
Matcher candidate = Pattern.compile("(structure101-build-java-all-)(.*).zip").matcher(anchor.getHrefAttribute());
|
||||
if (candidate.find()) {
|
||||
matcher = candidate;
|
||||
Matcher matcher = Pattern.compile("(structure101-build-java-all-)(.*).zip").matcher(anchor.getHrefAttribute());
|
||||
if (matcher.find()) {
|
||||
copyZipToFilesystem(source, installationDirectory, matcher.group(1) + matcher.group(2));
|
||||
return matcher.group(2);
|
||||
}
|
||||
}
|
||||
if (matcher == null) {
|
||||
return null;
|
||||
}
|
||||
copyZipToFilesystem(source, installationDirectory, matcher.group(1) + matcher.group(2));
|
||||
return matcher.group(2);
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
+388
@@ -0,0 +1,388 @@
|
||||
package io.spring.gradle.github.milestones;
|
||||
|
||||
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 static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
|
||||
public class GitHubMilestoneApiTests {
|
||||
private GitHubMilestoneApi github;
|
||||
|
||||
private RepositoryRef repositoryRef = RepositoryRef.owner("spring-projects").repository("spring-security").build();
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
this.github = new GitHubMilestoneApi("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 findMilestoneNumberByTitleWhenFoundThenSuccess() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
long milestoneNumberByTitle = this.github.findMilestoneNumberByTitle(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(milestoneNumberByTitle).isEqualTo(191);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findMilestoneNumberByTitleWhenNotFoundThenException() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.github.findMilestoneNumberByTitle(this.repositoryRef, "missing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isOpenIssuesForMilestoneNumberWhenAllClosedThenFalse() throws Exception {
|
||||
String responseJson = "[]";
|
||||
long milestoneNumber = 202;
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isFalse();
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isOpenIssuesForMilestoneNumberWhenOpenIssuesThenTrue() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562\",\n" +
|
||||
" \"repository_url\":\"https://api.github.com/repos/spring-projects/spring-security\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/labels{/name}\",\n" +
|
||||
" \"comments_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/comments\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/events\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" +
|
||||
" \"id\":851886504,\n" +
|
||||
" \"node_id\":\"MDExOlB1bGxSZXF1ZXN0NjEwMjMzMDcw\",\n" +
|
||||
" \"number\":9562,\n" +
|
||||
" \"title\":\"Add package-list\",\n" +
|
||||
" \"user\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"labels\":[\n" +
|
||||
" {\n" +
|
||||
" \"id\":322225043,\n" +
|
||||
" \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNDM=\",\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/in:%20build\",\n" +
|
||||
" \"name\":\"in: build\",\n" +
|
||||
" \"color\":\"e8f9de\",\n" +
|
||||
" \"default\":false,\n" +
|
||||
" \"description\":\"An issue in the build\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\":322225079,\n" +
|
||||
" \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNzk=\",\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/type:%20bug\",\n" +
|
||||
" \"name\":\"type: bug\",\n" +
|
||||
" \"color\":\"e3d9fc\",\n" +
|
||||
" \"default\":false,\n" +
|
||||
" \"description\":\"A general bug\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"locked\":false,\n" +
|
||||
" \"assignee\":{\n" +
|
||||
" \"login\":\"rwinch\",\n" +
|
||||
" \"id\":362503,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/rwinch\",\n" +
|
||||
" \"html_url\":\"https://github.com/rwinch\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"assignees\":[\n" +
|
||||
" {\n" +
|
||||
" \"login\":\"rwinch\",\n" +
|
||||
" \"id\":362503,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/rwinch\",\n" +
|
||||
" \"html_url\":\"https://github.com/rwinch\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"milestone\":{\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" \"comments\":0,\n" +
|
||||
" \"created_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-07T17:00:00Z\",\n" +
|
||||
" \"closed_at\":null,\n" +
|
||||
" \"author_association\":\"MEMBER\",\n" +
|
||||
" \"active_lock_reason\":null,\n" +
|
||||
" \"pull_request\":{\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/pulls/9562\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" +
|
||||
" \"diff_url\":\"https://github.com/spring-projects/spring-security/pull/9562.diff\",\n" +
|
||||
" \"patch_url\":\"https://github.com/spring-projects/spring-security/pull/9562.patch\"\n" +
|
||||
" },\n" +
|
||||
" \"body\":\"Closes gh-9528\\r\\n\\r\\n<!--\\r\\nFor Security Vulnerabilities, please use https://pivotal.io/security#reporting\\r\\n-->\\r\\n\\r\\n<!--\\r\\nBefore creating new features, we recommend creating an issue to discuss the feature. This ensures that everyone is on the same page before extensive work is done.\\r\\n\\r\\nThanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with gh-).\\r\\n-->\\r\\n\",\n" +
|
||||
" \"performed_via_github_app\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
long milestoneNumber = 191;
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isTrue();
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber);
|
||||
}
|
||||
|
||||
}
|
||||
+31
-31
@@ -15,16 +15,16 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIOException;
|
||||
|
||||
class AntoraVersionPluginTests {
|
||||
class CheckAntoraVersionPluginTests {
|
||||
|
||||
@Test
|
||||
void defaultsPropertiesWhenSnapshot() {
|
||||
String expectedVersion = "1.0.0-SNAPSHOT";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -40,9 +40,9 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0-M1";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -58,9 +58,9 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0-RC1";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -76,9 +76,9 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -92,9 +92,9 @@ class AntoraVersionPluginTests {
|
||||
@Test
|
||||
void explicitProperties() {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
checkAntoraVersionTask.getAntoraVersion().set("1.0.0");
|
||||
@@ -110,9 +110,9 @@ class AntoraVersionPluginTests {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -125,9 +125,9 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0-SNAPSHOT";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -142,9 +142,9 @@ class AntoraVersionPluginTests {
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -160,9 +160,9 @@ class AntoraVersionPluginTests {
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'\nprerelease: '-SNAPSHOT'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -177,9 +177,9 @@ class AntoraVersionPluginTests {
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0-M1'\nprerelease: 'true'\ndisplay_version: '1.0.0-M1'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -194,9 +194,9 @@ class AntoraVersionPluginTests {
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0-RC1'\nprerelease: 'true'\ndisplay_version: '1.0.0-RC1'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -211,9 +211,9 @@ class AntoraVersionPluginTests {
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -226,9 +226,9 @@ class AntoraVersionPluginTests {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
@@ -241,9 +241,9 @@ class AntoraVersionPluginTests {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'\nprerelease: '-SNAPSHOT'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
@@ -257,9 +257,9 @@ class AntoraVersionPluginTests {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("name: 'ROOT'\nversion: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
+1
-839
@@ -1,11 +1,5 @@
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
@@ -13,7 +7,7 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -389,836 +383,4 @@ public class GitHubMilestoneApiTests {
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenNotFoundThenException() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.github.isMilestoneDueToday(this.repositoryRef, "missing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenPastDueThenTrue() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(dueToday).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenDueTodayThenTrue() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"" + Instant.now().toString() + "\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(dueToday).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenNoDueDateThenFalse() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(dueToday).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenDueDateInFutureThenFalse() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"3000-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(dueToday).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenCurrentVersionIsNotSnapshotThenException() {
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-RC1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenPatchSegmentGreaterThan0ThenReturnsVersionWithoutSnapshot() {
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.1-SNAPSHOT");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenMilestoneAndRcExistThenReturnsMilestone() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.5.0-M1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"3000-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.0-M1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenTwoMilestonesExistThenReturnsSmallerMilestone() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.5.0-M9\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-M10\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"3000-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.0-M9");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenTwoRcsExistThenReturnsSmallerRc() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.5.0-RC9\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC10\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"3000-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.0-RC9");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenNoPreReleaseThenReturnsVersionWithoutSnapshot() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.4.3\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMilestoneWhenValidParametersThenSuccess() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(204));
|
||||
Milestone milestone = new Milestone();
|
||||
milestone.setTitle("1.0.0");
|
||||
milestone.setDueOn(LocalDate.of(2022, 5, 4).atTime(LocalTime.NOON));
|
||||
this.github.createMilestone(this.repositoryRef, milestone);
|
||||
|
||||
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/milestones");
|
||||
assertThat(recordedRequest.getBody().readString(Charset.defaultCharset()))
|
||||
.isEqualTo("{\"title\":\"1.0.0\",\"due_on\":\"2022-05-04T12:00:00Z\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMilestoneWhenErrorResponseThenException() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(400));
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.github.createMilestone(this.repositoryRef, new Milestone()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-245
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.Year;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import org.springframework.gradle.github.milestones.SpringReleaseTrainSpec.Train;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class SpringReleaseTrainTests {
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"2019-12-31, ONE, 2020",
|
||||
"2020-01-01, ONE, 2020",
|
||||
"2020-01-31, ONE, 2020",
|
||||
"2020-02-01, TWO, 2020",
|
||||
"2020-07-31, TWO, 2020",
|
||||
"2020-08-01, ONE, 2021"
|
||||
})
|
||||
public void nextTrainWhenBoundaryConditionsThenSuccess(LocalDate startDate, Train expectedTrain, Year expectedYear) {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.nextTrain(startDate)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.build();
|
||||
assertThat(releaseTrainSpec.getTrain()).isEqualTo(expectedTrain);
|
||||
assertThat(releaseTrainSpec.getYear()).isEqualTo(expectedYear);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainOneIsSecondTuesdayOf2020ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.year(2020)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2020, 1, 14));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2020, 2, 11));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2020, 3, 10));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2020, 4, 14));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2020, 5, 12));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainTwoIsSecondTuesdayOf2020ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(2)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.year(2020)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2020, 7, 14));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2020, 8, 11));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2020, 9, 15));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2020, 10, 13));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2020, 11, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainOneIsSecondTuesdayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 1, 11));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 2, 15));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 3, 15));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 4, 12));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 5, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainTwoIsSecondTuesdayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(2)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 7, 12));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 8, 9));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 9, 13));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 10, 11));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 11, 15));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainOneIsThirdMondayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(3)
|
||||
.dayOfWeek(1)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 1, 17));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 2, 21));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 3, 21));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 4, 18));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 5, 16));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainTwoIsThirdMondayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(2)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(3)
|
||||
.dayOfWeek(1)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 7, 18));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 8, 15));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 9, 19));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 10, 17));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 11, 21));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isTrainDateWhenTrainOneIsThirdMondayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(3)
|
||||
.dayOfWeek(1)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0-M1", LocalDate.of(2022, 1, dayOfMonth))).isEqualTo(dayOfMonth == 17);
|
||||
}
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 28; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0-M2", LocalDate.of(2022, 2, dayOfMonth))).isEqualTo(dayOfMonth == 21);
|
||||
}
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0-M3", LocalDate.of(2022, 3, dayOfMonth))).isEqualTo(dayOfMonth == 21);
|
||||
}
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 30; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0-RC1", LocalDate.of(2022, 4, dayOfMonth))).isEqualTo(dayOfMonth == 18);
|
||||
}
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0", LocalDate.of(2022, 5, dayOfMonth))).isEqualTo(dayOfMonth == 16);
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"2022-01-01, 2022-02-21",
|
||||
"2022-02-01, 2022-02-21",
|
||||
"2022-02-21, 2022-04-18",
|
||||
"2022-03-01, 2022-04-18",
|
||||
"2022-04-01, 2022-04-18",
|
||||
"2022-04-18, 2022-06-20",
|
||||
"2022-05-01, 2022-06-20",
|
||||
"2022-06-01, 2022-06-20",
|
||||
"2022-06-20, 2022-08-15",
|
||||
"2022-07-01, 2022-08-15",
|
||||
"2022-08-01, 2022-08-15",
|
||||
"2022-08-15, 2022-10-17",
|
||||
"2022-09-01, 2022-10-17",
|
||||
"2022-10-01, 2022-10-17",
|
||||
"2022-10-17, 2022-12-19",
|
||||
"2022-11-01, 2022-12-19",
|
||||
"2022-12-01, 2022-12-19",
|
||||
"2022-12-19, 2023-02-20"
|
||||
})
|
||||
public void getNextReleaseDateWhenBoundaryConditionsThenSuccess(LocalDate startDate, LocalDate expectedDate) {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(3)
|
||||
.dayOfWeek(1)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
assertThat(releaseTrain.getNextReleaseDate(startDate)).isEqualTo(expectedDate);
|
||||
}
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.github.release;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
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.RepositoryRef;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class GitHubActionsApiTests {
|
||||
private GitHubActionsApi gitHubActionsApi;
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
private RepositoryRef repository;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
this.baseUrl = this.server.url("/api").toString();
|
||||
this.gitHubActionsApi = new GitHubActionsApi("mock-oauth-token");
|
||||
this.gitHubActionsApi.setBaseUrl(this.baseUrl);
|
||||
this.repository = new RepositoryRef("spring-projects", "spring-security");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanup() throws Exception {
|
||||
this.server.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatchWorkflowWhenValidParametersThenSuccess() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(204));
|
||||
|
||||
Map<String, Object> inputs = new LinkedHashMap<>();
|
||||
inputs.put("input-1", "value");
|
||||
inputs.put("input-2", false);
|
||||
WorkflowDispatch workflowDispatch = new WorkflowDispatch("main", inputs);
|
||||
this.gitHubActionsApi.dispatchWorkflow(this.repository, "test-workflow.yml", workflowDispatch);
|
||||
|
||||
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/actions/workflows/test-workflow.yml/dispatches");
|
||||
assertThat(recordedRequest.getBody().readString(Charset.defaultCharset()))
|
||||
.isEqualTo("{\"ref\":\"main\",\"inputs\":{\"input-1\":\"value\",\"input-2\":false}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatchWorkflowWhenErrorResponseThenException() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(400));
|
||||
|
||||
WorkflowDispatch workflowDispatch = new WorkflowDispatch("main", null);
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.gitHubActionsApi.dispatchWorkflow(this.repository, "test-workflow.yml", workflowDispatch));
|
||||
}
|
||||
}
|
||||
-155
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.gradle.github.release;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
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.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 gitHubReleaseApi;
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
private RepositoryRef repository;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
this.baseUrl = this.server.url("/api").toString();
|
||||
this.gitHubReleaseApi = new GitHubReleaseApi("mock-oauth-token");
|
||||
this.gitHubReleaseApi.setBaseUrl(this.baseUrl);
|
||||
this.repository = new RepositoryRef("spring-projects", "spring-security");
|
||||
}
|
||||
|
||||
@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.gitHubReleaseApi.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().readString(Charset.defaultCharset()))
|
||||
.isEqualTo("{\"tag_name\":\"1.0.0\",\"draft\":false,\"prerelease\":false,\"generate_release_notes\":false}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishReleaseWhenErrorResponseThenException() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(400));
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.gitHubReleaseApi.publishRelease(this.repository, Release.tag("1.0.0").build()));
|
||||
}
|
||||
}
|
||||
+1
-19
@@ -42,8 +42,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.context.NullSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -207,8 +205,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
|
||||
private AuthenticationFailureHandler proxyFailureHandler = new SimpleUrlAuthenticationFailureHandler();
|
||||
|
||||
private SecurityContextRepository securityContextRepository = new NullSecurityContextRepository();
|
||||
|
||||
public CasAuthenticationFilter() {
|
||||
super("/login/cas");
|
||||
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
|
||||
@@ -227,7 +223,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
||||
context.setAuthentication(authResult);
|
||||
SecurityContextHolder.setContext(context);
|
||||
this.securityContextRepository.saveContext(context, request, response);
|
||||
if (this.eventPublisher != null) {
|
||||
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
|
||||
}
|
||||
@@ -251,8 +246,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
this.logger.debug("Failed to obtain an artifact (cas ticket)");
|
||||
password = "";
|
||||
}
|
||||
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
|
||||
password);
|
||||
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
|
||||
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
||||
return this.getAuthenticationManager().authenticate(authRequest);
|
||||
}
|
||||
@@ -280,18 +274,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SecurityContextRepository} to save the {@link SecurityContext} on
|
||||
* authentication success. The default action is not to save the
|
||||
* {@link SecurityContext}.
|
||||
* @param securityContextRepository the {@link SecurityContextRepository} to use.
|
||||
* Cannot be null.
|
||||
*/
|
||||
public void setSecurityContextRepository(SecurityContextRepository securityContextRepository) {
|
||||
Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");
|
||||
this.securityContextRepository = securityContextRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationFailureHandler} for proxy requests.
|
||||
* @param proxyFailureHandler
|
||||
|
||||
+12
-12
@@ -87,8 +87,8 @@ public class CasAuthenticationProviderTests {
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.afterPropertiesSet();
|
||||
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
|
||||
.unauthenticated(CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "ST-123");
|
||||
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
|
||||
@@ -120,8 +120,8 @@ public class CasAuthenticationProviderTests {
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
|
||||
.unauthenticated(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, "ST-456");
|
||||
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
|
||||
@@ -157,8 +157,8 @@ public class CasAuthenticationProviderTests {
|
||||
cap.setServiceProperties(serviceProperties);
|
||||
cap.afterPropertiesSet();
|
||||
String ticket = "ST-456";
|
||||
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
|
||||
.unauthenticated(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
|
||||
Authentication result = cap.authenticate(token);
|
||||
}
|
||||
|
||||
@@ -178,8 +178,8 @@ public class CasAuthenticationProviderTests {
|
||||
cap.setServiceProperties(serviceProperties);
|
||||
cap.afterPropertiesSet();
|
||||
String ticket = "ST-456";
|
||||
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
|
||||
.unauthenticated(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
|
||||
Authentication result = cap.authenticate(token);
|
||||
verify(validator).validate(ticket, serviceProperties.getService());
|
||||
serviceProperties.setAuthenticateAllArtifacts(true);
|
||||
@@ -211,8 +211,8 @@ public class CasAuthenticationProviderTests {
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
|
||||
.unauthenticated(CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "");
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER, "");
|
||||
assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> cap.authenticate(token));
|
||||
}
|
||||
|
||||
@@ -314,8 +314,8 @@ public class CasAuthenticationProviderTests {
|
||||
cap.setTicketValidator(new MockTicketValidator(true));
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken
|
||||
.authenticated("some_normal_user", "password", AuthorityUtils.createAuthorityList("ROLE_A"));
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("some_normal_user",
|
||||
"password", AuthorityUtils.createAuthorityList("ROLE_A"));
|
||||
assertThat(cap.authenticate(token)).isNull();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -121,8 +121,8 @@ public class CasAuthenticationTokenTests {
|
||||
final Assertion assertion = new AssertionImpl("test");
|
||||
CasAuthenticationToken token1 = new CasAuthenticationToken("key", makeUserDetails(), "Password", this.ROLES,
|
||||
makeUserDetails(), assertion);
|
||||
UsernamePasswordAuthenticationToken token2 = UsernamePasswordAuthenticationToken.authenticated("Test",
|
||||
"Password", this.ROLES);
|
||||
UsernamePasswordAuthenticationToken token2 = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
this.ROLES);
|
||||
assertThat(!token1.equals(token2)).isTrue();
|
||||
}
|
||||
|
||||
|
||||
-36
@@ -21,7 +21,6 @@ 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.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@@ -33,15 +32,12 @@ import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -186,38 +182,6 @@ public class CasAuthenticationFilterTests {
|
||||
verify(successHandler).onAuthenticationSuccess(request, response, authentication);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecurityContextHolder() throws Exception {
|
||||
SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.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.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setAuthenticationManager(manager);
|
||||
filter.setSecurityContextRepository(securityContextRepository);
|
||||
filter.afterPropertiesSet();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNotNull()
|
||||
.withFailMessage("Authentication should not be null");
|
||||
verify(chain).doFilter(request, response);
|
||||
// validate for when the filterProcessUrl matches
|
||||
filter.setFilterProcessesUrl(request.getServletPath());
|
||||
SecurityContextHolder.clearContext();
|
||||
filter.doFilter(request, response, chain);
|
||||
ArgumentCaptor<SecurityContext> contextArg = ArgumentCaptor.forClass(SecurityContext.class);
|
||||
verify(securityContextRepository).saveContext(contextArg.capture(), eq(request), eq(response));
|
||||
assertThat(contextArg.getValue().getAuthentication().getPrincipal()).isEqualTo(authentication.getName());
|
||||
}
|
||||
|
||||
// SEC-1592
|
||||
@Test
|
||||
public void testChainNotInvokedForProxyReceptor() throws Exception {
|
||||
|
||||
@@ -76,7 +76,6 @@ 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 "com.unboundid:unboundid-ldapsdk"
|
||||
testImplementation 'org.eclipse.persistence:javax.persistence'
|
||||
testImplementation('org.hibernate:hibernate-entitymanager') {
|
||||
exclude group: 'javax.activation', module: 'javax.activation-api'
|
||||
|
||||
-185
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.ldap;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.ldap.core.support.LdapContextSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
||||
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class EmbeddedLdapServerContextSourceFactoryBeanITests {
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
public void contextSourceFactoryBeanWhenEmbeddedServerThenAuthenticates() throws Exception {
|
||||
this.spring.register(FromEmbeddedLdapServerConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
|
||||
.andExpect(authenticated().withUsername("bob"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contextSourceFactoryBeanWhenPortZeroThenAuthenticates() throws Exception {
|
||||
this.spring.register(PortZeroConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
|
||||
.andExpect(authenticated().withUsername("bob"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contextSourceFactoryBeanWhenCustomLdifAndRootThenAuthenticates() throws Exception {
|
||||
this.spring.register(CustomLdifAndRootConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("pg").password("password")).andExpect(authenticated().withUsername("pg"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contextSourceFactoryBeanWhenCustomManagerDnThenAuthenticates() throws Exception {
|
||||
this.spring.register(CustomManagerDnConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
|
||||
.andExpect(authenticated().withUsername("bob"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contextSourceFactoryBeanWhenManagerDnAndNoPasswordThenException() {
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
|
||||
.isThrownBy(() -> this.spring.register(CustomManagerDnNoPasswordConfig.class).autowire())
|
||||
.withRootCauseInstanceOf(IllegalStateException.class)
|
||||
.withMessageContaining("managerPassword is required if managerDn is supplied");
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FromEmbeddedLdapServerConfig {
|
||||
|
||||
@Bean
|
||||
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
|
||||
return EmbeddedLdapServerContextSourceFactoryBean.fromEmbeddedLdapServer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PortZeroConfig {
|
||||
|
||||
@Bean
|
||||
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
|
||||
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
|
||||
.fromEmbeddedLdapServer();
|
||||
factoryBean.setPort(0);
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomLdifAndRootConfig {
|
||||
|
||||
@Bean
|
||||
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
|
||||
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
|
||||
.fromEmbeddedLdapServer();
|
||||
factoryBean.setLdif("classpath*:test-server2.xldif");
|
||||
factoryBean.setRoot("dc=monkeymachine,dc=co,dc=uk");
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=gorillas");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomManagerDnConfig {
|
||||
|
||||
@Bean
|
||||
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
|
||||
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
|
||||
.fromEmbeddedLdapServer();
|
||||
factoryBean.setManagerDn("uid=admin,ou=system");
|
||||
factoryBean.setManagerPassword("secret");
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
|
||||
LdapPasswordComparisonAuthenticationManagerFactory factory = new LdapPasswordComparisonAuthenticationManagerFactory(
|
||||
contextSource, NoOpPasswordEncoder.getInstance());
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomManagerDnNoPasswordConfig {
|
||||
|
||||
@Bean
|
||||
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
|
||||
EmbeddedLdapServerContextSourceFactoryBean factoryBean = EmbeddedLdapServerContextSourceFactoryBean
|
||||
.fromEmbeddedLdapServer();
|
||||
factoryBean.setManagerDn("uid=admin,ou=system");
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(LdapContextSource contextSource) {
|
||||
LdapPasswordComparisonAuthenticationManagerFactory factory = new LdapPasswordComparisonAuthenticationManagerFactory(
|
||||
contextSource, NoOpPasswordEncoder.getInstance());
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-241
@@ -1,241 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.ldap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
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.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.ldap.core.support.LdapContextSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
||||
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class LdapBindAuthenticationManagerFactoryITests {
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
public void authenticationManagerFactoryWhenFromContextSourceThenAuthenticates() throws Exception {
|
||||
this.spring.register(FromContextSourceConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
|
||||
.andExpect(authenticated().withUsername("bob"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ldapAuthenticationProviderCustomLdapAuthoritiesPopulator() throws Exception {
|
||||
CustomAuthoritiesPopulatorConfig.LAP = new DefaultLdapAuthoritiesPopulator(mock(LdapContextSource.class),
|
||||
null) {
|
||||
@Override
|
||||
protected Set<GrantedAuthority> getAdditionalRoles(DirContextOperations user, String username) {
|
||||
return new HashSet<>(AuthorityUtils.createAuthorityList("ROLE_EXTRA"));
|
||||
}
|
||||
};
|
||||
|
||||
this.spring.register(CustomAuthoritiesPopulatorConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(
|
||||
authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationManagerFactoryWhenCustomAuthoritiesMapperThenUsed() throws Exception {
|
||||
CustomAuthoritiesMapperConfig.AUTHORITIES_MAPPER = ((authorities) -> AuthorityUtils
|
||||
.createAuthorityList("ROLE_CUSTOM"));
|
||||
|
||||
this.spring.register(CustomAuthoritiesMapperConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(
|
||||
authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_CUSTOM"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationManagerFactoryWhenCustomUserDetailsContextMapperThenUsed() throws Exception {
|
||||
CustomUserDetailsContextMapperConfig.CONTEXT_MAPPER = new UserDetailsContextMapper() {
|
||||
@Override
|
||||
public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
return User.withUsername("other").password("password").roles("USER").build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
|
||||
}
|
||||
};
|
||||
|
||||
this.spring.register(CustomUserDetailsContextMapperConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
|
||||
.andExpect(authenticated().withUsername("other"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationManagerFactoryWhenCustomUserDnPatternsThenUsed() throws Exception {
|
||||
this.spring.register(CustomUserDnPatternsConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
|
||||
.andExpect(authenticated().withUsername("bob"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationManagerFactoryWhenCustomUserSearchThenUsed() throws Exception {
|
||||
this.spring.register(CustomUserSearchConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
|
||||
.andExpect(authenticated().withUsername("bob"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FromContextSourceConfig extends BaseLdapServerConfig {
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomAuthoritiesMapperConfig extends BaseLdapServerConfig {
|
||||
|
||||
static GrantedAuthoritiesMapper AUTHORITIES_MAPPER;
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
factory.setAuthoritiesMapper(AUTHORITIES_MAPPER);
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomAuthoritiesPopulatorConfig extends BaseLdapServerConfig {
|
||||
|
||||
static LdapAuthoritiesPopulator LAP;
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
factory.setLdapAuthoritiesPopulator(LAP);
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomUserDetailsContextMapperConfig extends BaseLdapServerConfig {
|
||||
|
||||
static UserDetailsContextMapper CONTEXT_MAPPER;
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
factory.setUserDetailsContextMapper(CONTEXT_MAPPER);
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomUserDnPatternsConfig extends BaseLdapServerConfig {
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomUserSearchConfig extends BaseLdapServerConfig {
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserSearchFilter("uid={0}");
|
||||
factory.setUserSearchBase("ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
abstract static class BaseLdapServerConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapServer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
|
||||
int port = container.getLocalPort();
|
||||
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
this.container.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.ldap;
|
||||
|
||||
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.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
||||
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class LdapPasswordComparisonAuthenticationManagerFactoryITests {
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
public void authenticationManagerFactoryWhenCustomPasswordEncoderThenUsed() throws Exception {
|
||||
this.spring.register(CustomPasswordEncoderConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bcrypt").password("password"))
|
||||
.andExpect(authenticated().withUsername("bcrypt"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationManagerFactoryWhenCustomPasswordAttributeThenUsed() throws Exception {
|
||||
this.spring.register(CustomPasswordAttributeConfig.class).autowire();
|
||||
|
||||
this.mockMvc.perform(formLogin().user("bob").password("bob")).andExpect(authenticated().withUsername("bob"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomPasswordEncoderConfig extends BaseLdapServerConfig {
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
|
||||
LdapPasswordComparisonAuthenticationManagerFactory factory = new LdapPasswordComparisonAuthenticationManagerFactory(
|
||||
contextSource, new BCryptPasswordEncoder());
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomPasswordAttributeConfig extends BaseLdapServerConfig {
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
|
||||
LdapPasswordComparisonAuthenticationManagerFactory factory = new LdapPasswordComparisonAuthenticationManagerFactory(
|
||||
contextSource, NoOpPasswordEncoder.getInstance());
|
||||
factory.setPasswordAttribute("uid");
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
abstract static class BaseLdapServerConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapServer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
|
||||
int port = container.getLocalPort();
|
||||
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
this.container.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+5
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -56,7 +56,7 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||
AuthenticationManager.class);
|
||||
Authentication auth = authenticationManager
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
|
||||
.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
|
||||
UserDetails ben = (UserDetails) auth.getPrincipal();
|
||||
assertThat(ben.getAuthorities()).hasSize(3);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||
AuthenticationManager.class);
|
||||
Authentication auth = authenticationManager
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
|
||||
.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
|
||||
|
||||
assertThat(auth).isNotNull();
|
||||
}
|
||||
@@ -104,8 +104,7 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||
|
||||
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||
AuthenticationManager.class);
|
||||
Authentication auth = authenticationManager
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "ben"));
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
|
||||
|
||||
assertThat(auth).isNotNull();
|
||||
}
|
||||
@@ -122,7 +121,7 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||
AuthenticationManager.class);
|
||||
Authentication auth = authenticationManager
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("bcrypt", "password"));
|
||||
.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", "password"));
|
||||
|
||||
assertThat(auth).isNotNull();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -138,10 +138,4 @@ public abstract class Elements {
|
||||
|
||||
public static final String PASSWORD_MANAGEMENT = "password-management";
|
||||
|
||||
public static final String RELYING_PARTY_REGISTRATIONS = "relying-party-registrations";
|
||||
|
||||
public static final String SAML2_LOGIN = "saml2-login";
|
||||
|
||||
public static final String SAML2_LOGOUT = "saml2-logout";
|
||||
|
||||
}
|
||||
|
||||
+3
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2009-2022 the original author or authors.
|
||||
* Copyright 2009-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,7 +47,6 @@ import org.springframework.security.config.method.InterceptMethodsBeanDefinition
|
||||
import org.springframework.security.config.method.MethodSecurityBeanDefinitionParser;
|
||||
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
|
||||
import org.springframework.security.config.oauth2.client.ClientRegistrationsBeanDefinitionParser;
|
||||
import org.springframework.security.config.saml2.RelyingPartyRegistrationsBeanDefinitionParser;
|
||||
import org.springframework.security.config.websocket.WebSocketMessageBrokerSecurityBeanDefinitionParser;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -95,7 +94,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
if (!namespaceMatchesVersion(element)) {
|
||||
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or "
|
||||
+ "spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
|
||||
+ "with Spring Security 5.7. Please update your schema declarations to the 5.7 schema.", element);
|
||||
+ "with Spring Security 5.6. Please update your schema declarations to the 5.6 schema.", element);
|
||||
}
|
||||
String name = pc.getDelegate().getLocalName(element);
|
||||
BeanDefinitionParser parser = this.parsers.get(name);
|
||||
@@ -191,7 +190,6 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
this.parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
|
||||
this.filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
|
||||
this.parsers.put(Elements.CLIENT_REGISTRATIONS, new ClientRegistrationsBeanDefinitionParser());
|
||||
this.parsers.put(Elements.RELYING_PARTY_REGISTRATIONS, new RelyingPartyRegistrationsBeanDefinitionParser());
|
||||
}
|
||||
|
||||
private void loadWebSocketParsers() {
|
||||
@@ -217,7 +215,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
private boolean matchesVersionInternal(Element element) {
|
||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||
return schemaLocation.matches("(?m).*spring-security-5\\.7.*.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-5\\.6.*.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
||||
+11
-29
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,19 +39,10 @@ import org.springframework.security.config.annotation.web.servlet.configuration.
|
||||
* @EnableGlobalAuthentication
|
||||
* public class MyGlobalAuthenticationConfiguration {
|
||||
*
|
||||
* @Bean
|
||||
* public UserDetailsService userDetailsService() {
|
||||
* UserDetails user = User.withDefaultPasswordEncoder()
|
||||
* .username("user")
|
||||
* .password("password")
|
||||
* .roles("USER")
|
||||
* .build();
|
||||
* UserDetails admin = User.withDefaultPasswordEncoder()
|
||||
* .username("admin")
|
||||
* .password("password")
|
||||
* .roles("ADMIN", "USER")
|
||||
* .build();
|
||||
* return new InMemoryUserDetailsManager(user, admin);
|
||||
* @Autowired
|
||||
* public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
* auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
* .and().withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
@@ -63,24 +54,15 @@ import org.springframework.security.config.annotation.web.servlet.configuration.
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @EnableWebSecurity
|
||||
* public class MyWebSecurityConfiguration {
|
||||
* public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
*
|
||||
* @Bean
|
||||
* public UserDetailsService userDetailsService() {
|
||||
* UserDetails user = User.withDefaultPasswordEncoder()
|
||||
* .username("user")
|
||||
* .password("password")
|
||||
* .roles("USER")
|
||||
* .build();
|
||||
* UserDetails admin = User.withDefaultPasswordEncoder()
|
||||
* .username("admin")
|
||||
* .password("password")
|
||||
* .roles("ADMIN", "USER")
|
||||
* .build();
|
||||
* return new InMemoryUserDetailsManager(user, admin);
|
||||
* @Autowired
|
||||
* public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
* auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
* .and().withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
* }
|
||||
*
|
||||
* // Possibly more bean methods ...
|
||||
* // Possibly overridden methods ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
|
||||
+23
-29
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,16 +17,16 @@
|
||||
package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
||||
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
|
||||
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
|
||||
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
|
||||
import org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager;
|
||||
@@ -45,64 +45,59 @@ import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
final class PrePostMethodSecurityConfiguration {
|
||||
final class PrePostMethodSecurityConfiguration implements ApplicationContextAware {
|
||||
|
||||
private final PreFilterAuthorizationMethodInterceptor preFilterAuthorizationMethodInterceptor = new PreFilterAuthorizationMethodInterceptor();
|
||||
|
||||
private final AuthorizationManagerBeforeMethodInterceptor preAuthorizeAuthorizationMethodInterceptor;
|
||||
|
||||
private final PreAuthorizeAuthorizationManager preAuthorizeAuthorizationManager = new PreAuthorizeAuthorizationManager();
|
||||
|
||||
private final AuthorizationManagerAfterMethodInterceptor postAuthorizeAuthorizaitonMethodInterceptor;
|
||||
|
||||
private final PostAuthorizeAuthorizationManager postAuthorizeAuthorizationManager = new PostAuthorizeAuthorizationManager();
|
||||
|
||||
private final PostFilterAuthorizationMethodInterceptor postFilterAuthorizationMethodInterceptor = new PostFilterAuthorizationMethodInterceptor();
|
||||
|
||||
private final DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
|
||||
@Autowired
|
||||
PrePostMethodSecurityConfiguration(ApplicationContext context) {
|
||||
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
|
||||
this.preAuthorizeAuthorizationMethodInterceptor = AuthorizationManagerBeforeMethodInterceptor
|
||||
.preAuthorize(this.preAuthorizeAuthorizationManager);
|
||||
this.postAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
|
||||
this.postAuthorizeAuthorizaitonMethodInterceptor = AuthorizationManagerAfterMethodInterceptor
|
||||
.postAuthorize(this.postAuthorizeAuthorizationManager);
|
||||
this.preFilterAuthorizationMethodInterceptor.setExpressionHandler(this.expressionHandler);
|
||||
this.postFilterAuthorizationMethodInterceptor.setExpressionHandler(this.expressionHandler);
|
||||
this.expressionHandler.setApplicationContext(context);
|
||||
AuthorizationEventPublisher publisher = new SpringAuthorizationEventPublisher(context);
|
||||
this.preAuthorizeAuthorizationMethodInterceptor.setAuthorizationEventPublisher(publisher);
|
||||
this.postAuthorizeAuthorizaitonMethodInterceptor.setAuthorizationEventPublisher(publisher);
|
||||
}
|
||||
private boolean customMethodSecurityExpressionHandler = false;
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
Advisor preFilterAuthorizationMethodInterceptor() {
|
||||
if (!this.customMethodSecurityExpressionHandler) {
|
||||
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
|
||||
}
|
||||
return this.preFilterAuthorizationMethodInterceptor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
Advisor preAuthorizeAuthorizationMethodInterceptor() {
|
||||
return this.preAuthorizeAuthorizationMethodInterceptor;
|
||||
if (!this.customMethodSecurityExpressionHandler) {
|
||||
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
|
||||
}
|
||||
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(this.preAuthorizeAuthorizationManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
Advisor postAuthorizeAuthorizationMethodInterceptor() {
|
||||
return this.postAuthorizeAuthorizaitonMethodInterceptor;
|
||||
if (!this.customMethodSecurityExpressionHandler) {
|
||||
this.postAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
|
||||
}
|
||||
return AuthorizationManagerAfterMethodInterceptor.postAuthorize(this.postAuthorizeAuthorizationManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
Advisor postFilterAuthorizationMethodInterceptor() {
|
||||
if (!this.customMethodSecurityExpressionHandler) {
|
||||
this.postFilterAuthorizationMethodInterceptor.setExpressionHandler(this.expressionHandler);
|
||||
}
|
||||
return this.postFilterAuthorizationMethodInterceptor;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
void setMethodSecurityExpressionHandler(MethodSecurityExpressionHandler methodSecurityExpressionHandler) {
|
||||
this.customMethodSecurityExpressionHandler = true;
|
||||
this.preFilterAuthorizationMethodInterceptor.setExpressionHandler(methodSecurityExpressionHandler);
|
||||
this.preAuthorizeAuthorizationManager.setExpressionHandler(methodSecurityExpressionHandler);
|
||||
this.postAuthorizeAuthorizationManager.setExpressionHandler(methodSecurityExpressionHandler);
|
||||
@@ -114,10 +109,9 @@ final class PrePostMethodSecurityConfiguration {
|
||||
this.expressionHandler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
void setAuthorizationEventPublisher(AuthorizationEventPublisher eventPublisher) {
|
||||
this.preAuthorizeAuthorizationMethodInterceptor.setAuthorizationEventPublisher(eventPublisher);
|
||||
this.postAuthorizeAuthorizaitonMethodInterceptor.setAuthorizationEventPublisher(eventPublisher);
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
this.expressionHandler.setApplicationContext(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-4
@@ -42,8 +42,6 @@ import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.DisableEncodeUrlFilter;
|
||||
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
|
||||
/**
|
||||
@@ -126,8 +124,6 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
|
||||
* The ordering of the Filters is:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link ForceEagerSessionCreationFilter}</li>
|
||||
* <li>{@link DisableEncodeUrlFilter}</li>
|
||||
* <li>{@link ChannelProcessingFilter}</li>
|
||||
* <li>{@link SecurityContextPersistenceFilter}</li>
|
||||
* <li>{@link LogoutFilter}</li>
|
||||
|
||||
+7
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,16 +23,19 @@ import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
/**
|
||||
* Allows customization to the {@link WebSecurity}. In most instances users will use
|
||||
* {@link EnableWebSecurity} and create a {@link Configuration} that exposes a
|
||||
* {@link SecurityFilterChain} bean. This will automatically be applied to the
|
||||
* {@link WebSecurity} by the {@link EnableWebSecurity} annotation.
|
||||
* {@link EnableWebSecurity} and either create a {@link Configuration} that extends
|
||||
* {@link WebSecurityConfigurerAdapter} or expose a {@link SecurityFilterChain} bean. Both
|
||||
* will automatically be applied to the {@link WebSecurity} by the
|
||||
* {@link EnableWebSecurity} annotation.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see WebSecurityConfigurerAdapter
|
||||
* @see SecurityFilterChain
|
||||
*/
|
||||
public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends SecurityConfigurer<Filter, T> {
|
||||
|
||||
-6
@@ -37,7 +37,6 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera
|
||||
import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
|
||||
import org.springframework.security.web.context.SecurityContextHolderFilter;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
||||
import org.springframework.security.web.csrf.CsrfFilter;
|
||||
@@ -46,8 +45,6 @@ import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.DisableEncodeUrlFilter;
|
||||
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
@@ -70,12 +67,9 @@ final class FilterOrderRegistration {
|
||||
|
||||
FilterOrderRegistration() {
|
||||
Step order = new Step(INITIAL_ORDER, ORDER_STEP);
|
||||
put(DisableEncodeUrlFilter.class, order.next());
|
||||
put(ForceEagerSessionCreationFilter.class, order.next());
|
||||
put(ChannelProcessingFilter.class, order.next());
|
||||
order.next(); // gh-8105
|
||||
put(WebAsyncManagerIntegrationFilter.class, order.next());
|
||||
put(SecurityContextHolderFilter.class, order.next());
|
||||
put(SecurityContextPersistenceFilter.class, order.next());
|
||||
put(HeaderWriterFilter.class, order.next());
|
||||
put(CorsFilter.class, order.next());
|
||||
|
||||
+406
-779
File diff suppressed because it is too large
Load Diff
+8
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.security.config.annotation.web.AbstractRequestMatcher
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
@@ -76,7 +77,8 @@ import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
*
|
||||
* <p>
|
||||
* Customizations to the {@link WebSecurity} can be made by creating a
|
||||
* {@link WebSecurityConfigurer} or exposing a {@link WebSecurityCustomizer} bean.
|
||||
* {@link WebSecurityConfigurer}, overriding {@link WebSecurityConfigurerAdapter} or
|
||||
* exposing a {@link WebSecurityCustomizer} bean.
|
||||
* </p>
|
||||
*
|
||||
* @author Rob Winch
|
||||
@@ -198,7 +200,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
*
|
||||
* <p>
|
||||
* Typically this method is invoked automatically within the framework from
|
||||
* {@link WebSecurityConfiguration#springSecurityFilterChain()}
|
||||
* {@link WebSecurityConfigurerAdapter#init(WebSecurity)}
|
||||
* </p>
|
||||
* @param securityFilterChainBuilder the builder to use to create the
|
||||
* {@link SecurityFilterChain} instances
|
||||
@@ -256,13 +258,12 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
|
||||
/**
|
||||
* Sets the {@link FilterSecurityInterceptor}. This is typically invoked by
|
||||
* {@link WebSecurityConfiguration#springSecurityFilterChain()}.
|
||||
* {@link WebSecurityConfigurerAdapter}.
|
||||
* @param securityInterceptor the {@link FilterSecurityInterceptor} to use
|
||||
* @return the {@link WebSecurity} for further customizations
|
||||
* @deprecated Use {@link #privilegeEvaluator(WebInvocationPrivilegeEvaluator)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public WebSecurity securityInterceptor(FilterSecurityInterceptor securityInterceptor) {
|
||||
this.filterSecurityInterceptor = securityInterceptor;
|
||||
return this;
|
||||
@@ -278,24 +279,12 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the handler to handle
|
||||
* {@link org.springframework.security.web.firewall.RequestRejectedException}
|
||||
* @param requestRejectedHandler
|
||||
* @return the {@link WebSecurity} for further customizations
|
||||
* @since 5.7
|
||||
*/
|
||||
public WebSecurity requestRejectedHandler(RequestRejectedHandler requestRejectedHandler) {
|
||||
Assert.notNull(requestRejectedHandler, "requestRejectedHandler cannot be null");
|
||||
this.requestRejectedHandler = requestRejectedHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Filter performBuild() throws Exception {
|
||||
Assert.state(!this.securityFilterChainBuilders.isEmpty(),
|
||||
() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
|
||||
+ "Typically this is done by exposing a SecurityFilterChain bean. "
|
||||
+ "Typically this is done by exposing a SecurityFilterChain bean "
|
||||
+ "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
|
||||
+ "More advanced users can invoke " + WebSecurity.class.getSimpleName()
|
||||
+ ".addSecurityFilterChainBuilder directly");
|
||||
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
|
||||
|
||||
+17
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,56 +26,48 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
/**
|
||||
* Add this annotation to an {@code @Configuration} class to have the Spring Security
|
||||
* configuration defined in any {@link WebSecurityConfigurer} or more likely by exposing a
|
||||
* {@link SecurityFilterChain} bean:
|
||||
* configuration defined in any {@link WebSecurityConfigurer} or more likely by extending
|
||||
* the {@link WebSecurityConfigurerAdapter} base class and overriding individual methods:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @EnableWebSecurity
|
||||
* public class MyWebSecurityConfiguration {
|
||||
* public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
*
|
||||
* @Bean
|
||||
* public WebSecurityCustomizer webSecurityCustomizer() {
|
||||
* return (web) -> web.ignoring()
|
||||
* @Override
|
||||
* public void configure(WebSecurity web) throws Exception {
|
||||
* web.ignoring()
|
||||
* // Spring Security should completely ignore URLs starting with /resources/
|
||||
* .antMatchers("/resources/**");
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
* @Override
|
||||
* protected void configure(HttpSecurity http) throws Exception {
|
||||
* http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest()
|
||||
* .hasRole("USER").and()
|
||||
* // Possibly more configuration ...
|
||||
* .formLogin() // enable form based log in
|
||||
* // set permitAll for all URLs associated with Form Login
|
||||
* .permitAll();
|
||||
* return http.build();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public UserDetailsService userDetailsService() {
|
||||
* UserDetails user = User.withDefaultPasswordEncoder()
|
||||
* .username("user")
|
||||
* .password("password")
|
||||
* .roles("USER")
|
||||
* .build();
|
||||
* UserDetails admin = User.withDefaultPasswordEncoder()
|
||||
* .username("admin")
|
||||
* .password("password")
|
||||
* .roles("ADMIN", "USER")
|
||||
* .build();
|
||||
* return new InMemoryUserDetailsManager(user, admin);
|
||||
* @Override
|
||||
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
* auth
|
||||
* // enable in memory based authentication with a user named "user" and "admin"
|
||||
* .inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
* .and().withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
* }
|
||||
*
|
||||
* // Possibly more bean methods ...
|
||||
* // Possibly more overridden methods ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see WebSecurityConfigurer
|
||||
* @see WebSecurityConfigurerAdapter
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
|
||||
+1
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -25,13 +24,11 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer;
|
||||
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
||||
|
||||
@@ -100,7 +97,6 @@ class HttpSecurityConfiguration {
|
||||
.apply(new DefaultLoginPageConfigurer<>());
|
||||
http.logout(withDefaults());
|
||||
// @formatter:on
|
||||
applyDefaultConfigurers(http);
|
||||
return http;
|
||||
}
|
||||
|
||||
@@ -109,15 +105,6 @@ class HttpSecurityConfiguration {
|
||||
: this.authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
private void applyDefaultConfigurers(HttpSecurity http) throws Exception {
|
||||
ClassLoader classLoader = this.context.getClassLoader();
|
||||
List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
|
||||
.loadFactories(AbstractHttpConfigurer.class, classLoader);
|
||||
for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
|
||||
http.apply(configurer);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Class<?>, Object> createSharedObjects() {
|
||||
Map<Class<?>, Object> sharedObjects = new HashMap<>();
|
||||
sharedObjects.put(ApplicationContext.class, this.context);
|
||||
|
||||
+31
-142
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,14 +16,10 @@
|
||||
|
||||
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;
|
||||
@@ -71,22 +67,17 @@ class SecurityReactorContextConfiguration {
|
||||
|
||||
private static final String SECURITY_REACTOR_CONTEXT_OPERATOR_KEY = "org.springframework.security.SECURITY_REACTOR_CONTEXT_OPERATOR";
|
||||
|
||||
private static final Map<Object, Supplier<Object>> CONTEXT_ATTRIBUTE_VALUE_LOADERS = new HashMap<>();
|
||||
|
||||
static {
|
||||
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletRequest.class,
|
||||
SecurityReactorContextSubscriberRegistrar::getRequest);
|
||||
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletResponse.class,
|
||||
SecurityReactorContextSubscriberRegistrar::getResponse);
|
||||
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(Authentication.class,
|
||||
SecurityReactorContextSubscriberRegistrar::getAuthentication);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Function<? super Publisher<Object>, ? extends Publisher<Object>> lifter = Operators
|
||||
.liftPublisher((pub, sub) -> createSubscriberIfNecessary(sub));
|
||||
Hooks.onLastOperator(SECURITY_REACTOR_CONTEXT_OPERATOR_KEY, lifter::apply);
|
||||
Hooks.onLastOperator(SECURITY_REACTOR_CONTEXT_OPERATOR_KEY, (pub) -> {
|
||||
if (!contextAttributesAvailable()) {
|
||||
// No need to decorate so return original Publisher
|
||||
return pub;
|
||||
}
|
||||
return lifter.apply(pub);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,30 +93,36 @@ class SecurityReactorContextConfiguration {
|
||||
return new SecurityReactorContextSubscriber<>(delegate, getContextAttributes());
|
||||
}
|
||||
|
||||
private static boolean contextAttributesAvailable() {
|
||||
return SecurityContextHolder.getContext().getAuthentication() != null
|
||||
|| RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes;
|
||||
}
|
||||
|
||||
private static Map<Object, Object> getContextAttributes() {
|
||||
return new LoadingMap<>(CONTEXT_ATTRIBUTE_VALUE_LOADERS);
|
||||
}
|
||||
|
||||
private static HttpServletRequest getRequest() {
|
||||
HttpServletRequest servletRequest = null;
|
||||
HttpServletResponse servletResponse = null;
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
if (requestAttributes instanceof ServletRequestAttributes) {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
|
||||
return servletRequestAttributes.getRequest();
|
||||
servletRequest = servletRequestAttributes.getRequest();
|
||||
servletResponse = servletRequestAttributes.getResponse(); // possible null
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static HttpServletResponse getResponse() {
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
if (requestAttributes instanceof ServletRequestAttributes) {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
|
||||
return servletRequestAttributes.getResponse(); // possible null
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null && servletRequest == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Object, Object> contextAttributes = new HashMap<>();
|
||||
if (servletRequest != null) {
|
||||
contextAttributes.put(HttpServletRequest.class, servletRequest);
|
||||
}
|
||||
if (servletResponse != null) {
|
||||
contextAttributes.put(HttpServletResponse.class, servletResponse);
|
||||
}
|
||||
if (authentication != null) {
|
||||
contextAttributes.put(Authentication.class, authentication);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Authentication getAuthentication() {
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
return contextAttributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -178,112 +175,4 @@ class SecurityReactorContextConfiguration {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A map that computes each value when {@link #get} is invoked
|
||||
*/
|
||||
static class LoadingMap<K, V> implements Map<K, V> {
|
||||
|
||||
private final Map<K, V> loaded = new ConcurrentHashMap<>();
|
||||
|
||||
private final Map<K, Supplier<V>> loaders;
|
||||
|
||||
LoadingMap(Map<K, Supplier<V>> loaders) {
|
||||
this.loaders = Collections.unmodifiableMap(new HashMap<>(loaders));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.loaders.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.loaders.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return this.loaders.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return this.loaders.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
if (!this.loaders.containsKey(key)) {
|
||||
throw new IllegalArgumentException(
|
||||
"This map only supports the following keys: " + this.loaders.keySet());
|
||||
}
|
||||
return this.loaded.computeIfAbsent((K) key, (k) -> this.loaders.get(k).get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
if (!this.loaders.containsKey(key)) {
|
||||
throw new IllegalArgumentException(
|
||||
"This map only supports the following keys: " + this.loaders.keySet());
|
||||
}
|
||||
return this.loaded.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
if (!this.loaders.containsKey(key)) {
|
||||
throw new IllegalArgumentException(
|
||||
"This map only supports the following keys: " + this.loaders.keySet());
|
||||
}
|
||||
return this.loaded.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.loaded.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return this.loaded.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return this.loaded.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return this.loaded.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadingMap<?, ?> that = (LoadingMap<?, ?>) o;
|
||||
|
||||
return this.loaded.equals(that.loaded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.loaded.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import javax.servlet.Filter;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -54,9 +55,10 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
|
||||
* based security for Spring Security. It then exports the necessary beans. Customizations
|
||||
* can be made to {@link WebSecurity} by implementing {@link WebSecurityConfigurer} and
|
||||
* exposing it as a {@link Configuration} or exposing a {@link WebSecurityCustomizer}
|
||||
* bean. This configuration is imported when using {@link EnableWebSecurity}.
|
||||
* can be made to {@link WebSecurity} by extending {@link WebSecurityConfigurerAdapter}
|
||||
* and exposing it as a {@link Configuration} or implementing
|
||||
* {@link WebSecurityConfigurer} and exposing it as a {@link Configuration}. This
|
||||
* configuration is imported when using {@link EnableWebSecurity}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Keesun Baik
|
||||
@@ -141,20 +143,19 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
|
||||
* instances used to create the web configuration.
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} used to create a
|
||||
* {@link WebSecurity} instance
|
||||
* @param beanFactory the bean factory to use to retrieve the relevant
|
||||
* @param webSecurityConfigurers the
|
||||
* {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to
|
||||
* create the web configuration
|
||||
* @throws Exception
|
||||
*/
|
||||
@Autowired(required = false)
|
||||
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
|
||||
ConfigurableListableBeanFactory beanFactory) throws Exception {
|
||||
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
|
||||
throws Exception {
|
||||
this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
|
||||
if (this.debugEnabled != null) {
|
||||
this.webSecurity.debug(this.debugEnabled);
|
||||
}
|
||||
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new AutowiredWebSecurityConfigurersIgnoreParents(
|
||||
beanFactory).getWebSecurityConfigurers();
|
||||
webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
|
||||
Integer previousOrder = null;
|
||||
Object previousConfig = null;
|
||||
@@ -188,6 +189,12 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
|
||||
return new RsaKeyConversionServicePostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
|
||||
ConfigurableListableBeanFactory beanFactory) {
|
||||
return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
Map<String, Object> enableWebSecurityAttrMap = importMetadata
|
||||
|
||||
+1
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -89,12 +89,8 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @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}
|
||||
*/
|
||||
@Order(100)
|
||||
@Deprecated
|
||||
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
|
||||
|
||||
private final Log logger = LogFactory.getLog(WebSecurityConfigurerAdapter.class);
|
||||
|
||||
+6
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,7 +25,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
@@ -38,7 +38,6 @@ import org.springframework.security.web.authentication.SavedRequestAwareAuthenti
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
@@ -147,11 +146,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
public T securityContextRepository(SecurityContextRepository securityContextRepository) {
|
||||
this.authFilter.setSecurityContextRepository(securityContextRepository);
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link RequestMatcher} given a loginProcessingUrl
|
||||
* @param loginProcessingUrl creates the {@link RequestMatcher} based upon the
|
||||
@@ -293,12 +287,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
if (rememberMeServices != null) {
|
||||
this.authFilter.setRememberMeServices(rememberMeServices);
|
||||
}
|
||||
SecurityContextConfigurer securityContextConfigurer = http.getConfigurer(SecurityContextConfigurer.class);
|
||||
if (securityContextConfigurer != null && securityContextConfigurer.isRequireExplicitSave()) {
|
||||
SecurityContextRepository securityContextRepository = securityContextConfigurer
|
||||
.getSecurityContextRepository();
|
||||
this.authFilter.setSecurityContextRepository(securityContextRepository);
|
||||
}
|
||||
F filter = postProcess(this.authFilter);
|
||||
http.addFilter(filter);
|
||||
}
|
||||
@@ -306,14 +294,14 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
/**
|
||||
* <p>
|
||||
* Specifies the URL to send users to if login is required. If used with
|
||||
* {@link EnableWebSecurity} a default login page will be generated when this
|
||||
* attribute is not specified.
|
||||
* {@link WebSecurityConfigurerAdapter} a default login page will be generated when
|
||||
* this attribute is not specified.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If a URL is specified or this is not being used in conjunction with
|
||||
* {@link EnableWebSecurity}, users are required to process the specified URL to
|
||||
* generate a login page.
|
||||
* {@link WebSecurityConfigurerAdapter}, users are required to process the specified
|
||||
* URL to generate a login page.
|
||||
* </p>
|
||||
*/
|
||||
protected T loginPage(String loginPage) {
|
||||
|
||||
+2
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,9 +25,7 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
@@ -36,7 +34,6 @@ import org.springframework.security.web.access.intercept.RequestAuthorizationCon
|
||||
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -49,25 +46,14 @@ import org.springframework.util.Assert;
|
||||
public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractHttpConfigurer<AuthorizeHttpRequestsConfigurer<H>, H> {
|
||||
|
||||
static final AuthorizationManager<RequestAuthorizationContext> permitAllAuthorizationManager = (a,
|
||||
o) -> new AuthorizationDecision(true);
|
||||
|
||||
private final AuthorizationManagerRequestMatcherRegistry registry;
|
||||
|
||||
private final AuthorizationEventPublisher publisher;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param context the {@link ApplicationContext} to use
|
||||
*/
|
||||
public AuthorizeHttpRequestsConfigurer(ApplicationContext context) {
|
||||
this.registry = new AuthorizationManagerRequestMatcherRegistry(context);
|
||||
if (context.getBeanNamesForType(AuthorizationEventPublisher.class).length > 0) {
|
||||
this.publisher = context.getBean(AuthorizationEventPublisher.class);
|
||||
}
|
||||
else {
|
||||
this.publisher = new SpringAuthorizationEventPublisher(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,8 +70,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
public void configure(H http) {
|
||||
AuthorizationManager<HttpServletRequest> authorizationManager = this.registry.createAuthorizationManager();
|
||||
AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
|
||||
authorizationFilter.setAuthorizationEventPublisher(this.publisher);
|
||||
authorizationFilter.setShouldFilterAllDispatcherTypes(this.registry.shouldFilterAllDispatcherTypes);
|
||||
http.addFilter(postProcess(authorizationFilter));
|
||||
}
|
||||
|
||||
@@ -97,12 +81,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
AuthorizationManagerRequestMatcherRegistry addFirst(RequestMatcher matcher,
|
||||
AuthorizationManager<RequestAuthorizationContext> manager) {
|
||||
this.registry.addFirst(matcher, manager);
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registry for mapping a {@link RequestMatcher} to an {@link AuthorizationManager}.
|
||||
*
|
||||
@@ -118,8 +96,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
|
||||
private int mappingCount;
|
||||
|
||||
private boolean shouldFilterAllDispatcherTypes = false;
|
||||
|
||||
private AuthorizationManagerRequestMatcherRegistry(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
@@ -130,12 +106,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
this.mappingCount++;
|
||||
}
|
||||
|
||||
private void addFirst(RequestMatcher matcher, AuthorizationManager<RequestAuthorizationContext> manager) {
|
||||
this.unmappedMatchers = null;
|
||||
this.managerBuilder.mappings((m) -> m.add(0, new RequestMatcherEntry<>(matcher, manager)));
|
||||
this.mappingCount++;
|
||||
}
|
||||
|
||||
private AuthorizationManager<HttpServletRequest> createAuthorizationManager() {
|
||||
Assert.state(this.unmappedMatchers == null,
|
||||
() -> "An incomplete mapping was found for " + this.unmappedMatchers
|
||||
@@ -173,19 +143,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether all dispatcher types should be filtered.
|
||||
* @param shouldFilter should filter all dispatcher types. Default is
|
||||
* {@code false}
|
||||
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
|
||||
* customizations
|
||||
* @since 5.7
|
||||
*/
|
||||
public AuthorizationManagerRequestMatcherRegistry shouldFilterAllDispatcherTypes(boolean shouldFilter) {
|
||||
this.shouldFilterAllDispatcherTypes = shouldFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link HttpSecurityBuilder} when done using the
|
||||
* {@link AuthorizeHttpRequestsConfigurer}. This is useful for method chaining.
|
||||
@@ -252,7 +209,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
* customizations
|
||||
*/
|
||||
public AuthorizationManagerRequestMatcherRegistry permitAll() {
|
||||
return access(permitAllAuthorizationManager);
|
||||
return access((a, o) -> new AuthorizationDecision(true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,9 +30,7 @@ import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.RedirectStrategy;
|
||||
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessor;
|
||||
@@ -77,7 +75,6 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
*
|
||||
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @author Rob Winch
|
||||
* @author Onur Kagan Ozcan
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
@@ -89,8 +86,6 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
private List<ChannelProcessor> channelProcessors;
|
||||
|
||||
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
|
||||
private final ChannelRequestMatcherRegistry REGISTRY;
|
||||
|
||||
/**
|
||||
@@ -128,11 +123,9 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
if (portMapper != null) {
|
||||
RetryWithHttpEntryPoint httpEntryPoint = new RetryWithHttpEntryPoint();
|
||||
httpEntryPoint.setPortMapper(portMapper);
|
||||
httpEntryPoint.setRedirectStrategy(this.redirectStrategy);
|
||||
insecureChannelProcessor.setEntryPoint(httpEntryPoint);
|
||||
RetryWithHttpsEntryPoint httpsEntryPoint = new RetryWithHttpsEntryPoint();
|
||||
httpsEntryPoint.setPortMapper(portMapper);
|
||||
httpsEntryPoint.setRedirectStrategy(this.redirectStrategy);
|
||||
secureChannelProcessor.setEntryPoint(httpsEntryPoint);
|
||||
}
|
||||
insecureChannelProcessor = postProcess(insecureChannelProcessor);
|
||||
@@ -192,17 +185,6 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link RedirectStrategy} instances to use in
|
||||
* {@link RetryWithHttpEntryPoint} and {@link RetryWithHttpsEntryPoint}
|
||||
* @param redirectStrategy
|
||||
* @return the {@link ChannelSecurityConfigurer} for further customizations
|
||||
*/
|
||||
public ChannelRequestMatcherRegistry redirectStrategy(RedirectStrategy redirectStrategy) {
|
||||
ChannelSecurityConfigurer.this.redirectStrategy = redirectStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link SecurityBuilder} when done using the
|
||||
* {@link SecurityConfigurer}. This is useful for method chaining.
|
||||
|
||||
+3
-3
@@ -237,8 +237,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Gets the default {@link AccessDeniedHandler} from the
|
||||
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler(HttpSecurityBuilder)} or
|
||||
* create a {@link AccessDeniedHandlerImpl} if not available.
|
||||
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler()} or create a
|
||||
* {@link AccessDeniedHandlerImpl} if not available.
|
||||
* @param http the {@link HttpSecurityBuilder}
|
||||
* @return the {@link AccessDeniedHandler}
|
||||
*/
|
||||
@@ -247,7 +247,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
ExceptionHandlingConfigurer<H> exceptionConfig = http.getConfigurer(ExceptionHandlingConfigurer.class);
|
||||
AccessDeniedHandler handler = null;
|
||||
if (exceptionConfig != null) {
|
||||
handler = exceptionConfig.getAccessDeniedHandler(http);
|
||||
handler = exceptionConfig.getAccessDeniedHandler();
|
||||
}
|
||||
if (handler == null) {
|
||||
handler = new AccessDeniedHandlerImpl();
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,7 @@ import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter;
|
||||
@@ -30,7 +30,7 @@ import org.springframework.security.web.csrf.CsrfToken;
|
||||
|
||||
/**
|
||||
* Adds a Filter that will generate a login page if one is not specified otherwise when
|
||||
* using {@link EnableWebSecurity}.
|
||||
* using {@link WebSecurityConfigurerAdapter}.
|
||||
*
|
||||
* <p>
|
||||
* By default an
|
||||
@@ -64,7 +64,7 @@ import org.springframework.security.web.csrf.CsrfToken;
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see EnableWebSecurity
|
||||
* @see WebSecurityConfigurerAdapter
|
||||
*/
|
||||
public final class DefaultLoginPageConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractHttpConfigurer<DefaultLoginPageConfigurer<H>, H> {
|
||||
|
||||
+3
-1
@@ -369,7 +369,9 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs requires a specific IP Address or subnet.
|
||||
* Specify that URLs requires a specific IP Address or <a href=
|
||||
* "https://forum.spring.io/showthread.php?102783-How-to-use-hasIpAddress&p=343971#post343971"
|
||||
* >subnet</a>.
|
||||
* @param ipaddressExpression the ipaddress (i.e. 192.168.1.79) or local subnet
|
||||
* (i.e. 192.168.0/24)
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
|
||||
@@ -84,15 +84,15 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
/**
|
||||
* <p>
|
||||
* Specifies the URL to send users to if login is required. If used with
|
||||
* {@link EnableWebSecurity} a default login page will be generated when this
|
||||
* attribute is not specified.
|
||||
* {@link WebSecurityConfigurerAdapter} a default login page will be generated when
|
||||
* this attribute is not specified.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If a URL is specified or this is not being used in conjunction with
|
||||
* {@link EnableWebSecurity}, users are required to process the specified URL to
|
||||
* generate a login page. In general, the login page should create a form that submits
|
||||
* a request with the following requirements to work with
|
||||
* {@link WebSecurityConfigurerAdapter}, users are required to process the specified
|
||||
* URL to generate a login page. In general, the login page should create a form that
|
||||
* submits a request with the following requirements to work with
|
||||
* {@link UsernamePasswordAuthenticationFilter}:
|
||||
* </p>
|
||||
*
|
||||
|
||||
+3
-230
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,14 +26,11 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.header.HeaderWriter;
|
||||
import org.springframework.security.web.header.HeaderWriterFilter;
|
||||
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
|
||||
import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
|
||||
@@ -50,7 +47,7 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* <p>
|
||||
* Adds the Security HTTP headers to the response. Security HTTP headers is activated by
|
||||
* default when using {@link EnableWebSecurity}'s default constructor.
|
||||
* default when using {@link WebSecurityConfigurerAdapter}'s default constructor.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
@@ -100,12 +97,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
private final PermissionsPolicyConfig permissionsPolicy = new PermissionsPolicyConfig();
|
||||
|
||||
private final CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy = new CrossOriginOpenerPolicyConfig();
|
||||
|
||||
private final CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy = new CrossOriginEmbedderPolicyConfig();
|
||||
|
||||
private final CrossOriginResourcePolicyConfig crossOriginResourcePolicy = new CrossOriginResourcePolicyConfig();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
@@ -401,9 +392,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
addIfNotNull(writers, this.referrerPolicy.writer);
|
||||
addIfNotNull(writers, this.featurePolicy.writer);
|
||||
addIfNotNull(writers, this.permissionsPolicy.writer);
|
||||
addIfNotNull(writers, this.crossOriginOpenerPolicy.writer);
|
||||
addIfNotNull(writers, this.crossOriginEmbedderPolicy.writer);
|
||||
addIfNotNull(writers, this.crossOriginResourcePolicy.writer);
|
||||
writers.addAll(this.headerWriters);
|
||||
return writers;
|
||||
}
|
||||
@@ -556,129 +544,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this.permissionsPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which
|
||||
* responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link CrossOriginOpenerPolicyConfig} for additional confniguration
|
||||
* @since 5.7
|
||||
* @see CrossOriginOpenerPolicyHeaderWriter
|
||||
*/
|
||||
public CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy() {
|
||||
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
|
||||
return this.crossOriginOpenerPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the
|
||||
* {@code Cross-Origin-Opener-Policy} header in the response using the supplied
|
||||
* policy.
|
||||
* <p>
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which
|
||||
* responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginOpenerPolicyHeaderWriter
|
||||
*/
|
||||
public HeadersConfigurer<H> crossOriginOpenerPolicy(
|
||||
Customizer<CrossOriginOpenerPolicyConfig> crossOriginOpenerPolicyCustomizer) {
|
||||
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
|
||||
crossOriginOpenerPolicyCustomizer.customize(this.crossOriginOpenerPolicy);
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter}
|
||||
* which is responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginEmbedderPolicyHeaderWriter
|
||||
*/
|
||||
public CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy() {
|
||||
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
|
||||
return this.crossOriginEmbedderPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the
|
||||
* {@code Cross-Origin-Embedder-Policy} header in the response using the supplied
|
||||
* policy.
|
||||
* <p>
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter}
|
||||
* which is responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginEmbedderPolicyHeaderWriter
|
||||
*/
|
||||
public HeadersConfigurer<H> crossOriginEmbedderPolicy(
|
||||
Customizer<CrossOriginEmbedderPolicyConfig> crossOriginEmbedderPolicyCustomizer) {
|
||||
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
|
||||
crossOriginEmbedderPolicyCustomizer.customize(this.crossOriginEmbedderPolicy);
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginResourcePolicyHeaderWriter}
|
||||
* which is responsible for writing the header:
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginResourcePolicyHeaderWriter
|
||||
*/
|
||||
public CrossOriginResourcePolicyConfig crossOriginResourcePolicy() {
|
||||
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
|
||||
return this.crossOriginResourcePolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the
|
||||
* {@code Cross-Origin-Resource-Policy} header in the response using the supplied
|
||||
* policy.
|
||||
* <p>
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginResourcePolicyHeaderWriter}
|
||||
* which is responsible for writing the header:
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginResourcePolicyHeaderWriter
|
||||
*/
|
||||
public HeadersConfigurer<H> crossOriginResourcePolicy(
|
||||
Customizer<CrossOriginResourcePolicyConfig> crossOriginResourcePolicyCustomizer) {
|
||||
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
|
||||
crossOriginResourcePolicyCustomizer.customize(this.crossOriginResourcePolicy);
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
public final class ContentTypeOptionsConfig {
|
||||
|
||||
private XContentTypeOptionsHeaderWriter writer;
|
||||
@@ -1277,96 +1142,4 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
}
|
||||
|
||||
public final class CrossOriginOpenerPolicyConfig {
|
||||
|
||||
private CrossOriginOpenerPolicyHeaderWriter writer;
|
||||
|
||||
public CrossOriginOpenerPolicyConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to be used in the {@code Cross-Origin-Opener-Policy} header
|
||||
* @param openerPolicy a {@code Cross-Origin-Opener-Policy}
|
||||
* @return the {@link CrossOriginOpenerPolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if openerPolicy is null
|
||||
*/
|
||||
public CrossOriginOpenerPolicyConfig policy(
|
||||
CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy openerPolicy) {
|
||||
this.writer.setPolicy(openerPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cross Origin Opener Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
*/
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class CrossOriginEmbedderPolicyConfig {
|
||||
|
||||
private CrossOriginEmbedderPolicyHeaderWriter writer;
|
||||
|
||||
public CrossOriginEmbedderPolicyConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to be used in the {@code Cross-Origin-Embedder-Policy} header
|
||||
* @param embedderPolicy a {@code Cross-Origin-Embedder-Policy}
|
||||
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional
|
||||
* configuration
|
||||
* @throws IllegalArgumentException if embedderPolicy is null
|
||||
*/
|
||||
public CrossOriginEmbedderPolicyConfig policy(
|
||||
CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy embedderPolicy) {
|
||||
this.writer.setPolicy(embedderPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cross-Origin-Embedder-Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
*/
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class CrossOriginResourcePolicyConfig {
|
||||
|
||||
private CrossOriginResourcePolicyHeaderWriter writer;
|
||||
|
||||
public CrossOriginResourcePolicyConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to be used in the {@code Cross-Origin-Resource-Policy} header
|
||||
* @param resourcePolicy a {@code Cross-Origin-Resource-Policy}
|
||||
* @return the {@link CrossOriginResourcePolicyConfig} for additional
|
||||
* configuration
|
||||
* @throws IllegalArgumentException if resourcePolicy is null
|
||||
*/
|
||||
public CrossOriginResourcePolicyConfig policy(
|
||||
CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy resourcePolicy) {
|
||||
this.writer.setPolicy(resourcePolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cross-Origin-Resource-Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
*/
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -48,22 +48,11 @@ final class PermitAllSupport {
|
||||
RequestMatcher... requestMatchers) {
|
||||
ExpressionUrlAuthorizationConfigurer<?> configurer = http
|
||||
.getConfigurer(ExpressionUrlAuthorizationConfigurer.class);
|
||||
AuthorizeHttpRequestsConfigurer<?> httpConfigurer = http.getConfigurer(AuthorizeHttpRequestsConfigurer.class);
|
||||
|
||||
boolean oneConfigurerPresent = configurer == null ^ httpConfigurer == null;
|
||||
Assert.state(oneConfigurerPresent,
|
||||
"permitAll only works with either HttpSecurity.authorizeRequests() or HttpSecurity.authorizeHttpRequests(). "
|
||||
+ "Please define one or the other but not both.");
|
||||
|
||||
Assert.state(configurer != null, "permitAll only works with HttpSecurity.authorizeRequests()");
|
||||
for (RequestMatcher matcher : requestMatchers) {
|
||||
if (matcher != null) {
|
||||
if (configurer != null) {
|
||||
configurer.getRegistry().addMapping(0, new UrlMapping(matcher,
|
||||
SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
|
||||
}
|
||||
else {
|
||||
httpConfigurer.addFirst(matcher, AuthorizeHttpRequestsConfigurer.permitAllAuthorizationManager);
|
||||
}
|
||||
configurer.getRegistry().addMapping(0, new UrlMapping(matcher,
|
||||
SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-33
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,12 +18,12 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
@@ -148,10 +148,11 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Specifies the {@link UserDetailsService} used to look up the {@link UserDetails}
|
||||
* when a remember me token is valid. When using a
|
||||
* {@link org.springframework.security.web.SecurityFilterChain} bean, the default is
|
||||
* to look for a {@link UserDetailsService} bean. Alternatively, one can populate
|
||||
* {@link #rememberMeServices(RememberMeServices)}.
|
||||
* when a remember me token is valid. The default is to use the
|
||||
* {@link UserDetailsService} found by invoking
|
||||
* {@link HttpSecurity#getSharedObject(Class)} which is set when using
|
||||
* {@link WebSecurityConfigurerAdapter#configure(AuthenticationManagerBuilder)}.
|
||||
* Alternatively, one can populate {@link #rememberMeServices(RememberMeServices)}.
|
||||
* @param userDetailsService the {@link UserDetailsService} to configure
|
||||
* @return the {@link RememberMeConfigurer} for further customization
|
||||
* @see AbstractRememberMeServices
|
||||
@@ -394,16 +395,15 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link UserDetailsService} to use. Either the explicitly configured
|
||||
* {@link UserDetailsService} from {@link #userDetailsService(UserDetailsService)}, a
|
||||
* shared object from {@link HttpSecurity#getSharedObject(Class)} or the
|
||||
* {@link UserDetailsService} bean.
|
||||
* Gets the {@link UserDetailsService} to use. Either the explicitly configure
|
||||
* {@link UserDetailsService} from {@link #userDetailsService(UserDetailsService)} or
|
||||
* a shared object from {@link HttpSecurity#getSharedObject(Class)}.
|
||||
* @param http {@link HttpSecurity} to get the shared {@link UserDetailsService}
|
||||
* @return the {@link UserDetailsService} to use
|
||||
*/
|
||||
private UserDetailsService getUserDetailsService(H http) {
|
||||
if (this.userDetailsService == null) {
|
||||
this.userDetailsService = getSharedOrBean(http, UserDetailsService.class);
|
||||
this.userDetailsService = http.getSharedObject(UserDetailsService.class);
|
||||
}
|
||||
Assert.state(this.userDetailsService != null,
|
||||
() -> "userDetailsService cannot be null. Invoke " + RememberMeConfigurer.class.getSimpleName()
|
||||
@@ -431,25 +431,4 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this.key;
|
||||
}
|
||||
|
||||
private <C> C getSharedOrBean(H http, Class<C> type) {
|
||||
C shared = http.getSharedObject(type);
|
||||
if (shared != null) {
|
||||
return shared;
|
||||
}
|
||||
return getBeanOrNull(type);
|
||||
}
|
||||
|
||||
private <T> T getBeanOrNull(Class<T> type) {
|
||||
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return context.getBean(type);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-39
@@ -22,10 +22,8 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextHolderFilter;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
|
||||
|
||||
/**
|
||||
* Allows persisting and restoring of the {@link SecurityContext} found on the
|
||||
@@ -64,8 +62,6 @@ import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
|
||||
public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractHttpConfigurer<SecurityContextConfigurer<H>, H> {
|
||||
|
||||
private boolean requireExplicitSave;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#securityContext()
|
||||
@@ -83,46 +79,23 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
public SecurityContextConfigurer<H> requireExplicitSave(boolean requireExplicitSave) {
|
||||
this.requireExplicitSave = requireExplicitSave;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isRequireExplicitSave() {
|
||||
return this.requireExplicitSave;
|
||||
}
|
||||
|
||||
SecurityContextRepository getSecurityContextRepository() {
|
||||
SecurityContextRepository securityContextRepository = getBuilder()
|
||||
.getSharedObject(SecurityContextRepository.class);
|
||||
if (securityContextRepository == null) {
|
||||
securityContextRepository = new HttpSessionSecurityContextRepository();
|
||||
}
|
||||
return securityContextRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void configure(H http) {
|
||||
SecurityContextRepository securityContextRepository = getSecurityContextRepository();
|
||||
if (this.requireExplicitSave) {
|
||||
SecurityContextHolderFilter securityContextHolderFilter = postProcess(
|
||||
new SecurityContextHolderFilter(securityContextRepository));
|
||||
http.addFilter(securityContextHolderFilter);
|
||||
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
|
||||
if (securityContextRepository == null) {
|
||||
securityContextRepository = new HttpSessionSecurityContextRepository();
|
||||
}
|
||||
else {
|
||||
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
|
||||
securityContextRepository);
|
||||
SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
|
||||
SessionCreationPolicy sessionCreationPolicy = (sessionManagement != null)
|
||||
? sessionManagement.getSessionCreationPolicy() : null;
|
||||
if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {
|
||||
securityContextFilter.setForceEagerSessionCreation(true);
|
||||
http.addFilter(postProcess(new ForceEagerSessionCreationFilter()));
|
||||
}
|
||||
securityContextFilter = postProcess(securityContextFilter);
|
||||
http.addFilter(securityContextFilter);
|
||||
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
|
||||
securityContextRepository);
|
||||
SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
|
||||
SessionCreationPolicy sessionCreationPolicy = (sessionManagement != null)
|
||||
? sessionManagement.getSessionCreationPolicy() : null;
|
||||
if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {
|
||||
securityContextFilter.setForceEagerSessionCreation(true);
|
||||
}
|
||||
securityContextFilter = postProcess(securityContextFilter);
|
||||
http.addFilter(securityContextFilter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-14
@@ -52,8 +52,6 @@ import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.DisableEncodeUrlFilter;
|
||||
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
|
||||
import org.springframework.security.web.session.InvalidSessionStrategy;
|
||||
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
@@ -203,12 +201,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* {@link HttpServletResponse#encodeRedirectURL(String)} or
|
||||
* {@link HttpServletResponse#encodeURL(String)}, otherwise disallows HTTP sessions to
|
||||
* be included in the URL. This prevents leaking information to external domains.
|
||||
* <p>
|
||||
* This is achieved by guarding {@link HttpServletResponse#encodeURL} and
|
||||
* {@link HttpServletResponse#encodeRedirectURL} invocations. Any code that also
|
||||
* overrides either of these two methods, like
|
||||
* {@link org.springframework.web.servlet.resource.ResourceUrlEncodingFilter}, needs
|
||||
* to come after the security filter chain or risk being skipped.
|
||||
* @param enableSessionUrlRewriting true if should allow the JSESSIONID to be
|
||||
* rewritten into the URLs, else false (default)
|
||||
* @return the {@link SessionManagementConfigurer} for further customization
|
||||
@@ -378,12 +370,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
concurrentSessionFilter = postProcess(concurrentSessionFilter);
|
||||
http.addFilter(concurrentSessionFilter);
|
||||
}
|
||||
if (!this.enableSessionUrlRewriting) {
|
||||
http.addFilter(new DisableEncodeUrlFilter());
|
||||
}
|
||||
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
|
||||
http.addFilter(new ForceEagerSessionCreationFilter());
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentSessionFilter createConcurrencyFilter(H http) {
|
||||
|
||||
+4
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,6 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
@@ -142,7 +140,8 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Specifies the {@link AuthenticationUserDetailsService} to use. If not specified,
|
||||
* then the {@link UserDetailsService} bean will be used by default.
|
||||
* the shared {@link UserDetailsService} will be used to create a
|
||||
* {@link UserDetailsByNameServiceWrapper}.
|
||||
* @param authenticationUserDetailsService the
|
||||
* {@link AuthenticationUserDetailsService} to use
|
||||
* @return the {@link X509Configurer} for further customizations
|
||||
@@ -201,30 +200,9 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
|
||||
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> getAuthenticationUserDetailsService(
|
||||
H http) {
|
||||
if (this.authenticationUserDetailsService == null) {
|
||||
userDetailsService(getSharedOrBean(http, UserDetailsService.class));
|
||||
userDetailsService(http.getSharedObject(UserDetailsService.class));
|
||||
}
|
||||
return this.authenticationUserDetailsService;
|
||||
}
|
||||
|
||||
private <C> C getSharedOrBean(H http, Class<C> type) {
|
||||
C shared = http.getSharedObject(type);
|
||||
if (shared != null) {
|
||||
return shared;
|
||||
}
|
||||
return getBeanOrNull(type);
|
||||
}
|
||||
|
||||
private <T> T getBeanOrNull(Class<T> type) {
|
||||
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return context.getBean(type);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-15
@@ -18,9 +18,6 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.se
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -28,7 +25,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||
@@ -55,9 +51,6 @@ import org.springframework.security.oauth2.server.resource.web.DefaultBearerToke
|
||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
||||
import org.springframework.security.web.csrf.CsrfException;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||
@@ -160,19 +153,12 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
|
||||
private OpaqueTokenConfigurer opaqueTokenConfigurer;
|
||||
|
||||
private AccessDeniedHandler accessDeniedHandler = new DelegatingAccessDeniedHandler(
|
||||
new LinkedHashMap<>(createAccessDeniedHandlers()), new BearerTokenAccessDeniedHandler());
|
||||
private AccessDeniedHandler accessDeniedHandler = new BearerTokenAccessDeniedHandler();
|
||||
|
||||
private AuthenticationEntryPoint authenticationEntryPoint = new BearerTokenAuthenticationEntryPoint();
|
||||
|
||||
private BearerTokenRequestMatcher requestMatcher = new BearerTokenRequestMatcher();
|
||||
|
||||
private static Map<Class<? extends AccessDeniedException>, AccessDeniedHandler> createAccessDeniedHandlers() {
|
||||
Map<Class<? extends AccessDeniedException>, AccessDeniedHandler> handlers = new HashMap<>();
|
||||
handlers.put(CsrfException.class, new AccessDeniedHandlerImpl());
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public OAuth2ResourceServerConfigurer(ApplicationContext context) {
|
||||
Assert.notNull(context, "context cannot be null");
|
||||
this.context = context;
|
||||
|
||||
+18
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,7 +31,7 @@ import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
|
||||
@@ -61,29 +61,29 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
* <h2>Example Configuration</h2>
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* @Configuration
|
||||
* @EnableWebSecurity
|
||||
* public class OpenIDLoginConfig {
|
||||
* public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
|
||||
*
|
||||
* @Bean
|
||||
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
* @Override
|
||||
* protected void configure(HttpSecurity http) {
|
||||
* http
|
||||
* .authorizeRequests()
|
||||
* .antMatchers("/**").hasRole("USER")
|
||||
* .and()
|
||||
* .openidLogin()
|
||||
* .permitAll();
|
||||
* return http.build();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public UserDetailsService userDetailsService() {
|
||||
* UserDetails user = User.withDefaultPasswordEncoder()
|
||||
* .username("https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU")
|
||||
* .password("password")
|
||||
* .roles("USER")
|
||||
* .build();
|
||||
* return new InMemoryUserDetailsManager(user);
|
||||
* @Override
|
||||
* protected void configure(AuthenticationManagerBuilder auth)(
|
||||
* AuthenticationManagerBuilder auth) throws Exception {
|
||||
* auth
|
||||
* .inMemoryAuthentication()
|
||||
* .withUser("https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU")
|
||||
* .password("password")
|
||||
* .roles("USER");
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
@@ -229,14 +229,14 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* <p>
|
||||
* Specifies the URL to send users to if login is required. If used with
|
||||
* {@link EnableWebSecurity} a default login page will be generated when this
|
||||
* attribute is not specified.
|
||||
* {@link WebSecurityConfigurerAdapter} a default login page will be generated when
|
||||
* this attribute is not specified.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If a URL is specified or this is not being used in conjunction with
|
||||
* {@link EnableWebSecurity}, users are required to process the specified URL to
|
||||
* generate a login page.
|
||||
* {@link WebSecurityConfigurerAdapter}, users are required to process the specified
|
||||
* URL to generate a login page.
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
|
||||
+54
-74
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.security.config.annotation.web.configurers.saml2;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.opensaml.core.Version;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
@@ -48,7 +50,6 @@ import org.springframework.security.saml2.provider.service.web.RelyingPartyRegis
|
||||
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestContextResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
@@ -114,12 +115,10 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
private String loginPage;
|
||||
|
||||
private String authenticationRequestUri = "/saml2/authenticate/{registrationId}";
|
||||
|
||||
private Saml2AuthenticationRequestResolver authenticationRequestResolver;
|
||||
|
||||
private String loginProcessingUrl = Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
|
||||
|
||||
private AuthenticationRequestEndpointConfig authenticationRequestEndpoint = new AuthenticationRequestEndpointConfig();
|
||||
|
||||
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
|
||||
|
||||
private AuthenticationConverter authenticationConverter;
|
||||
@@ -177,20 +176,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this {@link Saml2AuthenticationRequestResolver} for generating SAML 2.0
|
||||
* Authentication Requests.
|
||||
* @param authenticationRequestResolver
|
||||
* @return the {@link Saml2LoginConfigurer} for further configuration
|
||||
* @since 5.7
|
||||
*/
|
||||
public Saml2LoginConfigurer<B> authenticationRequestResolver(
|
||||
Saml2AuthenticationRequestResolver authenticationRequestResolver) {
|
||||
Assert.notNull(authenticationRequestResolver, "authenticationRequestResolver cannot be null");
|
||||
this.authenticationRequestResolver = authenticationRequestResolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the URL to validate the credentials. If specified a custom URL, consider
|
||||
* specifying a custom {@link AuthenticationConverter} via
|
||||
@@ -215,7 +200,7 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
*
|
||||
* Initializes this filter chain for SAML 2 Login. The following actions are taken:
|
||||
* <ul>
|
||||
* <li>The WebSSO endpoint has CSRF disabled, typically {@code /login/saml2/sso}</li>
|
||||
@@ -241,8 +226,8 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
super.init(http);
|
||||
}
|
||||
else {
|
||||
Map<String, String> providerUrlMap = getIdentityProviderUrlMap(this.authenticationRequestUri,
|
||||
this.relyingPartyRegistrationRepository);
|
||||
Map<String, String> providerUrlMap = getIdentityProviderUrlMap(
|
||||
this.authenticationRequestEndpoint.filterProcessingUrl, this.relyingPartyRegistrationRepository);
|
||||
boolean singleProvider = providerUrlMap.size() == 1;
|
||||
if (singleProvider) {
|
||||
// Setup auto-redirect to provider login page
|
||||
@@ -262,16 +247,14 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
*
|
||||
* During the {@code configure} phase, a
|
||||
* {@link Saml2WebSsoAuthenticationRequestFilter} is added to handle SAML 2.0
|
||||
* AuthNRequest redirects
|
||||
*/
|
||||
@Override
|
||||
public void configure(B http) throws Exception {
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = getAuthenticationRequestFilter(http);
|
||||
filter.setAuthenticationRequestRepository(getAuthenticationRequestRepository(http));
|
||||
http.addFilter(postProcess(filter));
|
||||
http.addFilter(this.authenticationRequestEndpoint.build(http));
|
||||
super.configure(http);
|
||||
if (this.authenticationManager == null) {
|
||||
registerDefaultAuthenticationProvider(http);
|
||||
@@ -281,11 +264,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
}
|
||||
}
|
||||
|
||||
private RelyingPartyRegistrationResolver relyingPartyRegistrationResolver(B http) {
|
||||
RelyingPartyRegistrationRepository registrations = relyingPartyRegistrationRepository(http);
|
||||
return new DefaultRelyingPartyRegistrationResolver(registrations);
|
||||
}
|
||||
|
||||
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository(B http) {
|
||||
if (this.relyingPartyRegistrationRepository == null) {
|
||||
this.relyingPartyRegistrationRepository = getSharedOrBean(http, RelyingPartyRegistrationRepository.class);
|
||||
@@ -298,46 +276,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
saml2WebSsoAuthenticationFilter.setAuthenticationRequestRepository(getAuthenticationRequestRepository(http));
|
||||
}
|
||||
|
||||
private Saml2WebSsoAuthenticationRequestFilter getAuthenticationRequestFilter(B http) {
|
||||
Saml2AuthenticationRequestResolver authenticationRequestResolver = getAuthenticationRequestResolver(http);
|
||||
if (authenticationRequestResolver != null) {
|
||||
return new Saml2WebSsoAuthenticationRequestFilter(authenticationRequestResolver);
|
||||
}
|
||||
return new Saml2WebSsoAuthenticationRequestFilter(getAuthenticationRequestContextResolver(http),
|
||||
getAuthenticationRequestFactory(http));
|
||||
}
|
||||
|
||||
private Saml2AuthenticationRequestResolver getAuthenticationRequestResolver(B http) {
|
||||
if (this.authenticationRequestResolver != null) {
|
||||
return this.authenticationRequestResolver;
|
||||
}
|
||||
return getBeanOrNull(http, Saml2AuthenticationRequestResolver.class);
|
||||
}
|
||||
|
||||
private Saml2AuthenticationRequestFactory getAuthenticationRequestFactory(B http) {
|
||||
Saml2AuthenticationRequestFactory resolver = getSharedOrBean(http, Saml2AuthenticationRequestFactory.class);
|
||||
if (resolver != null) {
|
||||
return resolver;
|
||||
}
|
||||
if (version().startsWith("4")) {
|
||||
return new OpenSaml4AuthenticationRequestFactory();
|
||||
}
|
||||
else {
|
||||
return new OpenSamlAuthenticationRequestFactory();
|
||||
}
|
||||
}
|
||||
|
||||
private Saml2AuthenticationRequestContextResolver getAuthenticationRequestContextResolver(B http) {
|
||||
Saml2AuthenticationRequestContextResolver resolver = getBeanOrNull(http,
|
||||
Saml2AuthenticationRequestContextResolver.class);
|
||||
if (resolver != null) {
|
||||
return resolver;
|
||||
}
|
||||
RelyingPartyRegistrationResolver registrationResolver = new DefaultRelyingPartyRegistrationResolver(
|
||||
this.relyingPartyRegistrationRepository);
|
||||
return new DefaultSaml2AuthenticationRequestContextResolver(registrationResolver);
|
||||
}
|
||||
|
||||
private AuthenticationConverter getAuthenticationConverter(B http) {
|
||||
if (this.authenticationConverter != null) {
|
||||
return this.authenticationConverter;
|
||||
@@ -386,8 +324,8 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return;
|
||||
}
|
||||
loginPageGeneratingFilter.setSaml2LoginEnabled(true);
|
||||
loginPageGeneratingFilter.setSaml2AuthenticationUrlToProviderName(
|
||||
this.getIdentityProviderUrlMap(this.authenticationRequestUri, this.relyingPartyRegistrationRepository));
|
||||
loginPageGeneratingFilter.setSaml2AuthenticationUrlToProviderName(this.getIdentityProviderUrlMap(
|
||||
this.authenticationRequestEndpoint.filterProcessingUrl, this.relyingPartyRegistrationRepository));
|
||||
loginPageGeneratingFilter.setLoginPageUrl(this.getLoginPage());
|
||||
loginPageGeneratingFilter.setFailureUrl(this.getFailureUrl());
|
||||
}
|
||||
@@ -441,4 +379,46 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
}
|
||||
}
|
||||
|
||||
private final class AuthenticationRequestEndpointConfig {
|
||||
|
||||
private String filterProcessingUrl = "/saml2/authenticate/{registrationId}";
|
||||
|
||||
private AuthenticationRequestEndpointConfig() {
|
||||
}
|
||||
|
||||
private Filter build(B http) {
|
||||
Saml2AuthenticationRequestFactory authenticationRequestResolver = getResolver(http);
|
||||
Saml2AuthenticationRequestContextResolver contextResolver = getContextResolver(http);
|
||||
Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> repository = getAuthenticationRequestRepository(
|
||||
http);
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(contextResolver,
|
||||
authenticationRequestResolver);
|
||||
filter.setAuthenticationRequestRepository(repository);
|
||||
return postProcess(filter);
|
||||
}
|
||||
|
||||
private Saml2AuthenticationRequestFactory getResolver(B http) {
|
||||
Saml2AuthenticationRequestFactory resolver = getSharedOrBean(http, Saml2AuthenticationRequestFactory.class);
|
||||
if (resolver == null) {
|
||||
if (version().startsWith("4")) {
|
||||
return new OpenSaml4AuthenticationRequestFactory();
|
||||
}
|
||||
return new OpenSamlAuthenticationRequestFactory();
|
||||
}
|
||||
return resolver;
|
||||
}
|
||||
|
||||
private Saml2AuthenticationRequestContextResolver getContextResolver(B http) {
|
||||
Saml2AuthenticationRequestContextResolver resolver = getBeanOrNull(http,
|
||||
Saml2AuthenticationRequestContextResolver.class);
|
||||
if (resolver == null) {
|
||||
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(
|
||||
Saml2LoginConfigurer.this.relyingPartyRegistrationRepository);
|
||||
return new DefaultSaml2AuthenticationRequestContextResolver(relyingPartyRegistrationResolver);
|
||||
}
|
||||
return resolver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
|
||||
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProvider;
|
||||
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProviderBuilder;
|
||||
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
|
||||
@@ -42,7 +41,6 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve
|
||||
* This {@code Configuration} is imported by {@link EnableWebFluxSecurity}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Alavudin Kuttikkattil
|
||||
* @since 5.1
|
||||
*/
|
||||
final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
|
||||
@@ -66,12 +64,14 @@ final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
|
||||
|
||||
private ReactiveOAuth2AuthorizedClientService authorizedClientService;
|
||||
|
||||
private ReactiveOAuth2AuthorizedClientManager authorizedClientManager;
|
||||
|
||||
@Override
|
||||
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
|
||||
ReactiveOAuth2AuthorizedClientManager authorizedClientManager = getAuthorizedClientManager();
|
||||
if (authorizedClientManager != null) {
|
||||
if (this.authorizedClientRepository != null && this.clientRegistrationRepository != null) {
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().authorizationCode().refreshToken().clientCredentials().password().build();
|
||||
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
|
||||
this.clientRegistrationRepository, getAuthorizedClientRepository());
|
||||
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
|
||||
configurer.addCustomResolver(new OAuth2AuthorizedClientArgumentResolver(authorizedClientManager));
|
||||
}
|
||||
}
|
||||
@@ -93,13 +93,6 @@ final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
void setAuthorizedClientManager(List<ReactiveOAuth2AuthorizedClientManager> authorizedClientManager) {
|
||||
if (authorizedClientManager.size() == 1) {
|
||||
this.authorizedClientManager = authorizedClientManager.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() {
|
||||
if (this.authorizedClientRepository != null) {
|
||||
return this.authorizedClientRepository;
|
||||
@@ -110,23 +103,6 @@ final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ReactiveOAuth2AuthorizedClientManager getAuthorizedClientManager() {
|
||||
if (this.authorizedClientManager != null) {
|
||||
return this.authorizedClientManager;
|
||||
}
|
||||
ReactiveOAuth2AuthorizedClientManager authorizedClientManager = null;
|
||||
if (this.authorizedClientRepository != null && this.clientRegistrationRepository != null) {
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().authorizationCode().refreshToken().clientCredentials().password().build();
|
||||
DefaultReactiveOAuth2AuthorizedClientManager defaultReactiveOAuth2AuthorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
|
||||
this.clientRegistrationRepository, getAuthorizedClientRepository());
|
||||
defaultReactiveOAuth2AuthorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
|
||||
authorizedClientManager = defaultReactiveOAuth2AuthorizedClientManager;
|
||||
}
|
||||
|
||||
return authorizedClientManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-3
@@ -102,9 +102,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
pc.getRegistry().registerAlias(id, alias);
|
||||
pc.getReaderContext().fireAliasRegistered(id, alias, pc.extractSource(element));
|
||||
}
|
||||
if (!BeanIds.AUTHENTICATION_MANAGER.equals(id)
|
||||
&& !pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)
|
||||
&& !pc.getRegistry().isAlias(BeanIds.AUTHENTICATION_MANAGER)) {
|
||||
if (!BeanIds.AUTHENTICATION_MANAGER.equals(id)) {
|
||||
pc.getRegistry().registerAlias(id, BeanIds.AUTHENTICATION_MANAGER);
|
||||
pc.getReaderContext().fireAliasRegistered(id, BeanIds.AUTHENTICATION_MANAGER, pc.extractSource(element));
|
||||
}
|
||||
|
||||
+15
-122
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -164,8 +164,6 @@ final class AuthenticationConfigBuilder {
|
||||
@SuppressWarnings("rawtypes")
|
||||
private ManagedList logoutHandlers;
|
||||
|
||||
private BeanMetadataElement logoutSuccessHandler;
|
||||
|
||||
private BeanDefinition loginPageGenerationFilter;
|
||||
|
||||
private BeanDefinition logoutPageGenerationFilter;
|
||||
@@ -204,20 +202,6 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
private BeanDefinition oauth2LoginLinks;
|
||||
|
||||
private BeanDefinition saml2AuthenticationUrlToProviderName;
|
||||
|
||||
private BeanDefinition saml2AuthorizationRequestFilter;
|
||||
|
||||
private String saml2AuthenticationFilterId;
|
||||
|
||||
private String saml2AuthenticationRequestFilterId;
|
||||
|
||||
private String saml2LogoutFilterId;
|
||||
|
||||
private String saml2LogoutRequestFilterId;
|
||||
|
||||
private String saml2LogoutResponseFilterId;
|
||||
|
||||
private boolean oauth2ClientEnabled;
|
||||
|
||||
private BeanDefinition authorizationRequestRedirectFilter;
|
||||
@@ -236,8 +220,8 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
AuthenticationConfigBuilder(Element element, boolean forceAutoConfig, ParserContext pc,
|
||||
SessionCreationPolicy sessionPolicy, BeanReference requestCache, BeanReference authenticationManager,
|
||||
BeanReference authenticationFilterSecurityContextRepositoryRef, BeanReference sessionStrategy,
|
||||
BeanReference portMapper, BeanReference portResolver, BeanMetadataElement csrfLogoutHandler) {
|
||||
BeanReference sessionStrategy, BeanReference portMapper, BeanReference portResolver,
|
||||
BeanMetadataElement csrfLogoutHandler) {
|
||||
this.httpElt = element;
|
||||
this.pc = pc;
|
||||
this.requestCache = requestCache;
|
||||
@@ -251,16 +235,12 @@ final class AuthenticationConfigBuilder {
|
||||
createRememberMeFilter(authenticationManager);
|
||||
createBasicFilter(authenticationManager);
|
||||
createBearerTokenAuthenticationFilter(authenticationManager);
|
||||
createFormLoginFilter(sessionStrategy, authenticationManager, authenticationFilterSecurityContextRepositoryRef);
|
||||
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager,
|
||||
authenticationFilterSecurityContextRepositoryRef);
|
||||
createOpenIDLoginFilter(sessionStrategy, authenticationManager,
|
||||
authenticationFilterSecurityContextRepositoryRef);
|
||||
createSaml2LoginFilter(authenticationManager, authenticationFilterSecurityContextRepositoryRef);
|
||||
createFormLoginFilter(sessionStrategy, authenticationManager);
|
||||
createOAuth2ClientFilters(sessionStrategy, requestCache, authenticationManager);
|
||||
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
|
||||
createX509Filter(authenticationManager);
|
||||
createJeeFilter(authenticationManager);
|
||||
createLogoutFilter();
|
||||
createSaml2LogoutFilter();
|
||||
createLoginPageFilterIfNeeded();
|
||||
createUserDetailsServiceFactory();
|
||||
createExceptionTranslationFilter();
|
||||
@@ -292,8 +272,7 @@ final class AuthenticationConfigBuilder {
|
||||
this.rememberMeProviderRef = new RuntimeBeanReference(id);
|
||||
}
|
||||
|
||||
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager,
|
||||
BeanReference authenticationFilterSecurityContextRepositoryRef) {
|
||||
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.FORM_LOGIN);
|
||||
RootBeanDefinition formFilter = null;
|
||||
if (formLoginElt != null || this.autoConfig) {
|
||||
@@ -309,10 +288,6 @@ final class AuthenticationConfigBuilder {
|
||||
if (formFilter != null) {
|
||||
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", this.allowSessionCreation);
|
||||
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||
if (authenticationFilterSecurityContextRepositoryRef != null) {
|
||||
formFilter.getPropertyValues().addPropertyValue("securityContextRepository",
|
||||
authenticationFilterSecurityContextRepositoryRef);
|
||||
}
|
||||
// Id is required by login page filter
|
||||
this.formFilterId = this.pc.getReaderContext().generateBeanName(formFilter);
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(formFilter, this.formFilterId));
|
||||
@@ -321,15 +296,13 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
|
||||
void createOAuth2ClientFilters(BeanReference sessionStrategy, BeanReference requestCache,
|
||||
BeanReference authenticationManager, BeanReference authenticationFilterSecurityContextRepositoryRef) {
|
||||
createOAuth2LoginFilter(sessionStrategy, authenticationManager,
|
||||
authenticationFilterSecurityContextRepositoryRef);
|
||||
createOAuth2ClientFilter(requestCache, authenticationManager, authenticationFilterSecurityContextRepositoryRef);
|
||||
BeanReference authenticationManager) {
|
||||
createOAuth2LoginFilter(sessionStrategy, authenticationManager);
|
||||
createOAuth2ClientFilter(requestCache, authenticationManager);
|
||||
registerOAuth2ClientPostProcessors();
|
||||
}
|
||||
|
||||
void createOAuth2LoginFilter(BeanReference sessionStrategy, BeanReference authManager,
|
||||
BeanReference authenticationFilterSecurityContextRepositoryRef) {
|
||||
void createOAuth2LoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||
Element oauth2LoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OAUTH2_LOGIN);
|
||||
if (oauth2LoginElt == null) {
|
||||
return;
|
||||
@@ -341,10 +314,6 @@ final class AuthenticationConfigBuilder {
|
||||
BeanDefinition defaultAuthorizedClientRepository = parser.getDefaultAuthorizedClientRepository();
|
||||
registerDefaultAuthorizedClientRepositoryIfNecessary(defaultAuthorizedClientRepository);
|
||||
oauth2LoginFilterBean.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||
if (authenticationFilterSecurityContextRepositoryRef != null) {
|
||||
oauth2LoginFilterBean.getPropertyValues().addPropertyValue("securityContextRepository",
|
||||
authenticationFilterSecurityContextRepositoryRef);
|
||||
}
|
||||
|
||||
// retrieve the other bean result
|
||||
BeanDefinition oauth2LoginAuthProvider = parser.getOAuth2LoginAuthenticationProvider();
|
||||
@@ -374,15 +343,14 @@ final class AuthenticationConfigBuilder {
|
||||
this.oauth2LoginOidcAuthenticationProviderRef = new RuntimeBeanReference(oauth2LoginOidcAuthProviderId);
|
||||
}
|
||||
|
||||
void createOAuth2ClientFilter(BeanReference requestCache, BeanReference authenticationManager,
|
||||
BeanReference authenticationFilterSecurityContextRepositoryRef) {
|
||||
void createOAuth2ClientFilter(BeanReference requestCache, BeanReference authenticationManager) {
|
||||
Element oauth2ClientElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OAUTH2_CLIENT);
|
||||
if (oauth2ClientElt == null) {
|
||||
return;
|
||||
}
|
||||
this.oauth2ClientEnabled = true;
|
||||
OAuth2ClientBeanDefinitionParser parser = new OAuth2ClientBeanDefinitionParser(requestCache,
|
||||
authenticationManager, authenticationFilterSecurityContextRepositoryRef);
|
||||
authenticationManager);
|
||||
parser.parse(oauth2ClientElt, this.pc);
|
||||
BeanDefinition defaultAuthorizedClientRepository = parser.getDefaultAuthorizedClientRepository();
|
||||
registerDefaultAuthorizedClientRepositoryIfNecessary(defaultAuthorizedClientRepository);
|
||||
@@ -427,8 +395,7 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager,
|
||||
BeanReference authenticationFilterSecurityContextRepositoryRef) {
|
||||
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OPENID_LOGIN);
|
||||
RootBeanDefinition openIDFilter = null;
|
||||
if (openIDLoginElt != null) {
|
||||
@@ -437,10 +404,6 @@ final class AuthenticationConfigBuilder {
|
||||
if (openIDFilter != null) {
|
||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", this.allowSessionCreation);
|
||||
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||
if (authenticationFilterSecurityContextRepositoryRef != null) {
|
||||
openIDFilter.getPropertyValues().addPropertyValue("securityContextRepository",
|
||||
authenticationFilterSecurityContextRepositoryRef);
|
||||
}
|
||||
// Required by login page filter
|
||||
this.openIDFilterId = this.pc.getReaderContext().generateBeanName(openIDFilter);
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(openIDFilter, this.openIDFilterId));
|
||||
@@ -449,31 +412,6 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void createSaml2LoginFilter(BeanReference authenticationManager,
|
||||
BeanReference authenticationFilterSecurityContextRepositoryRef) {
|
||||
Element saml2LoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.SAML2_LOGIN);
|
||||
if (saml2LoginElt == null) {
|
||||
return;
|
||||
}
|
||||
Saml2LoginBeanDefinitionParser parser = new Saml2LoginBeanDefinitionParser(this.csrfIgnoreRequestMatchers,
|
||||
this.portMapper, this.portResolver, this.requestCache, this.allowSessionCreation, authenticationManager,
|
||||
authenticationFilterSecurityContextRepositoryRef, this.authenticationProviders,
|
||||
this.defaultEntryPointMappings);
|
||||
BeanDefinition saml2WebSsoAuthenticationFilter = parser.parse(saml2LoginElt, this.pc);
|
||||
this.saml2AuthorizationRequestFilter = parser.getSaml2WebSsoAuthenticationRequestFilter();
|
||||
|
||||
this.saml2AuthenticationFilterId = this.pc.getReaderContext().generateBeanName(saml2WebSsoAuthenticationFilter);
|
||||
this.saml2AuthenticationRequestFilterId = this.pc.getReaderContext()
|
||||
.generateBeanName(this.saml2AuthorizationRequestFilter);
|
||||
this.saml2AuthenticationUrlToProviderName = parser.getSaml2AuthenticationUrlToProviderName();
|
||||
|
||||
// register the component
|
||||
this.pc.registerBeanComponent(
|
||||
new BeanComponentDefinition(saml2WebSsoAuthenticationFilter, this.saml2AuthenticationFilterId));
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(this.saml2AuthorizationRequestFilter,
|
||||
this.saml2AuthenticationRequestFilterId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses OpenID 1.0 and 2.0 - related parts of configuration xmls
|
||||
* @param sessionStrategy sessionStrategy
|
||||
@@ -728,12 +666,6 @@ final class AuthenticationConfigBuilder {
|
||||
loginPageFilter.addPropertyValue("Oauth2LoginEnabled", true);
|
||||
loginPageFilter.addPropertyValue("Oauth2AuthenticationUrlToClientName", this.oauth2LoginLinks);
|
||||
}
|
||||
if (this.saml2AuthenticationFilterId != null) {
|
||||
loginPageFilter.addConstructorArgReference(this.saml2AuthenticationFilterId);
|
||||
loginPageFilter.addPropertyValue("saml2LoginEnabled", true);
|
||||
loginPageFilter.addPropertyValue("saml2AuthenticationUrlToProviderName",
|
||||
this.saml2AuthenticationUrlToProviderName);
|
||||
}
|
||||
this.loginPageGenerationFilter = loginPageFilter.getBeanDefinition();
|
||||
this.logoutPageGenerationFilter = logoutPageFilter.getBeanDefinition();
|
||||
}
|
||||
@@ -750,33 +682,9 @@ final class AuthenticationConfigBuilder {
|
||||
this.rememberMeServicesId, this.csrfLogoutHandler);
|
||||
this.logoutFilter = logoutParser.parse(logoutElt, this.pc);
|
||||
this.logoutHandlers = logoutParser.getLogoutHandlers();
|
||||
this.logoutSuccessHandler = logoutParser.getLogoutSuccessHandler();
|
||||
}
|
||||
}
|
||||
|
||||
private void createSaml2LogoutFilter() {
|
||||
Element saml2LogoutElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.SAML2_LOGOUT);
|
||||
if (saml2LogoutElt == null) {
|
||||
return;
|
||||
}
|
||||
Saml2LogoutBeanDefinitionParser parser = new Saml2LogoutBeanDefinitionParser(this.logoutHandlers,
|
||||
this.logoutSuccessHandler);
|
||||
parser.parse(saml2LogoutElt, this.pc);
|
||||
BeanDefinition saml2LogoutFilter = parser.getLogoutFilter();
|
||||
BeanDefinition saml2LogoutRequestFilter = parser.getLogoutRequestFilter();
|
||||
BeanDefinition saml2LogoutResponseFilter = parser.getLogoutResponseFilter();
|
||||
this.saml2LogoutFilterId = this.pc.getReaderContext().generateBeanName(saml2LogoutFilter);
|
||||
this.saml2LogoutRequestFilterId = this.pc.getReaderContext().generateBeanName(saml2LogoutRequestFilter);
|
||||
this.saml2LogoutResponseFilterId = this.pc.getReaderContext().generateBeanName(saml2LogoutResponseFilter);
|
||||
|
||||
// register the component
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(saml2LogoutFilter, this.saml2LogoutFilterId));
|
||||
this.pc.registerBeanComponent(
|
||||
new BeanComponentDefinition(saml2LogoutRequestFilter, this.saml2LogoutRequestFilterId));
|
||||
this.pc.registerBeanComponent(
|
||||
new BeanComponentDefinition(saml2LogoutResponseFilter, this.saml2LogoutResponseFilterId));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
ManagedList getLogoutHandlers() {
|
||||
if (this.logoutHandlers == null && this.rememberMeProviderRef != null) {
|
||||
@@ -932,8 +840,7 @@ final class AuthenticationConfigBuilder {
|
||||
if (formLoginElt != null && this.oauth2LoginEntryPoint != null) {
|
||||
return this.formEntryPoint;
|
||||
}
|
||||
// If form login was enabled through auto-config, and Oauth2 login & Saml2
|
||||
// login was not
|
||||
// If form login was enabled through auto-config, and Oauth2 login was not
|
||||
// enabled then use form login
|
||||
if (this.oauth2LoginEntryPoint == null) {
|
||||
return this.formEntryPoint;
|
||||
@@ -1016,20 +923,6 @@ final class AuthenticationConfigBuilder {
|
||||
filters.add(new OrderDecorator(this.authorizationCodeGrantFilter,
|
||||
SecurityFilters.OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER));
|
||||
}
|
||||
if (this.saml2AuthenticationFilterId != null) {
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2AuthenticationFilterId),
|
||||
SecurityFilters.SAML2_AUTHENTICATION_FILTER));
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2AuthenticationRequestFilterId),
|
||||
SecurityFilters.SAML2_AUTHENTICATION_REQUEST_FILTER));
|
||||
}
|
||||
if (this.saml2LogoutFilterId != null) {
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2LogoutFilterId),
|
||||
SecurityFilters.SAML2_LOGOUT_FILTER));
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2LogoutRequestFilterId),
|
||||
SecurityFilters.SAML2_LOGOUT_REQUEST_FILTER));
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(this.saml2LogoutResponseFilterId),
|
||||
SecurityFilters.SAML2_LOGOUT_RESPONSE_FILTER));
|
||||
}
|
||||
filters.add(new OrderDecorator(this.etf, SecurityFilters.EXCEPTION_TRANSLATION_FILTER));
|
||||
return filters;
|
||||
}
|
||||
|
||||
+1
-82
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,9 +36,6 @@ import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.web.header.HeaderWriterFilter;
|
||||
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
|
||||
import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
|
||||
@@ -125,12 +122,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private static final String PERMISSIONS_POLICY_ELEMENT = "permissions-policy";
|
||||
|
||||
private static final String CROSS_ORIGIN_OPENER_POLICY_ELEMENT = "cross-origin-opener-policy";
|
||||
|
||||
private static final String CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT = "cross-origin-embedder-policy";
|
||||
|
||||
private static final String CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT = "cross-origin-resource-policy";
|
||||
|
||||
private static final String ALLOW_FROM = "ALLOW-FROM";
|
||||
|
||||
private ManagedList<BeanMetadataElement> headerWriters;
|
||||
@@ -153,9 +144,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
parseReferrerPolicyElement(element, parserContext);
|
||||
parseFeaturePolicyElement(element, parserContext);
|
||||
parsePermissionsPolicyElement(element, parserContext);
|
||||
parseCrossOriginOpenerPolicy(disabled, element);
|
||||
parseCrossOriginEmbedderPolicy(disabled, element);
|
||||
parseCrossOriginResourcePolicy(disabled, element);
|
||||
parseHeaderElements(element);
|
||||
boolean noWriters = this.headerWriters.isEmpty();
|
||||
if (disabled && !noWriters) {
|
||||
@@ -388,75 +376,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
this.headerWriters.add(headersWriter.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void parseCrossOriginOpenerPolicy(boolean elementDisabled, Element element) {
|
||||
if (elementDisabled || element == null) {
|
||||
return;
|
||||
}
|
||||
CrossOriginOpenerPolicyHeaderWriter writer = new CrossOriginOpenerPolicyHeaderWriter();
|
||||
Element crossOriginOpenerPolicyElement = DomUtils.getChildElementByTagName(element,
|
||||
CROSS_ORIGIN_OPENER_POLICY_ELEMENT);
|
||||
if (crossOriginOpenerPolicyElement != null) {
|
||||
addCrossOriginOpenerPolicy(crossOriginOpenerPolicyElement, writer);
|
||||
}
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(CrossOriginOpenerPolicyHeaderWriter.class, () -> writer);
|
||||
this.headerWriters.add(builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void parseCrossOriginEmbedderPolicy(boolean elementDisabled, Element element) {
|
||||
if (elementDisabled || element == null) {
|
||||
return;
|
||||
}
|
||||
CrossOriginEmbedderPolicyHeaderWriter writer = new CrossOriginEmbedderPolicyHeaderWriter();
|
||||
Element crossOriginEmbedderPolicyElement = DomUtils.getChildElementByTagName(element,
|
||||
CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT);
|
||||
if (crossOriginEmbedderPolicyElement != null) {
|
||||
addCrossOriginEmbedderPolicy(crossOriginEmbedderPolicyElement, writer);
|
||||
}
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(CrossOriginEmbedderPolicyHeaderWriter.class, () -> writer);
|
||||
this.headerWriters.add(builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void parseCrossOriginResourcePolicy(boolean elementDisabled, Element element) {
|
||||
if (elementDisabled || element == null) {
|
||||
return;
|
||||
}
|
||||
CrossOriginResourcePolicyHeaderWriter writer = new CrossOriginResourcePolicyHeaderWriter();
|
||||
Element crossOriginResourcePolicyElement = DomUtils.getChildElementByTagName(element,
|
||||
CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT);
|
||||
if (crossOriginResourcePolicyElement != null) {
|
||||
addCrossOriginResourcePolicy(crossOriginResourcePolicyElement, writer);
|
||||
}
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(CrossOriginResourcePolicyHeaderWriter.class, () -> writer);
|
||||
this.headerWriters.add(builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void addCrossOriginResourcePolicy(Element crossOriginResourcePolicyElement,
|
||||
CrossOriginResourcePolicyHeaderWriter writer) {
|
||||
String policy = crossOriginResourcePolicyElement.getAttribute(ATT_POLICY);
|
||||
if (StringUtils.hasText(policy)) {
|
||||
writer.setPolicy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.from(policy));
|
||||
}
|
||||
}
|
||||
|
||||
private void addCrossOriginEmbedderPolicy(Element crossOriginEmbedderPolicyElement,
|
||||
CrossOriginEmbedderPolicyHeaderWriter writer) {
|
||||
String policy = crossOriginEmbedderPolicyElement.getAttribute(ATT_POLICY);
|
||||
if (StringUtils.hasText(policy)) {
|
||||
writer.setPolicy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.from(policy));
|
||||
}
|
||||
}
|
||||
|
||||
private void addCrossOriginOpenerPolicy(Element crossOriginOpenerPolicyElement,
|
||||
CrossOriginOpenerPolicyHeaderWriter writer) {
|
||||
String policy = crossOriginOpenerPolicyElement.getAttribute(ATT_POLICY);
|
||||
if (StringUtils.hasText(policy)) {
|
||||
writer.setPolicy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.from(policy));
|
||||
}
|
||||
}
|
||||
|
||||
private void attrNotAllowed(ParserContext context, String attrName, String otherAttrName, Element element) {
|
||||
context.getReaderContext().error("Only one of '" + attrName + "' or '" + otherAttrName + "' can be set.",
|
||||
element);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user