1
0
mirror of synced 2026-07-10 21:30:04 +00:00

Compare commits

...

10 Commits

Author SHA1 Message Date
Rob Winch ccb5f916e0 rm .github/workflows for unsupported branch 2025-05-02 12:35:23 -05:00
Steve Riesenberg c453c82948 Allow env vars to determine Artifactory repoKey
Closes gh-14250
2023-12-05 18:02:25 -06:00
Steve Riesenberg f6843b2bd9 Use env var to determine Artifactory URL
Closes gh-14246
2023-12-05 13:33:45 -06:00
Josh Cummings 4e37499e28 Merge branch '5.8.x' into 6.0.x 2023-12-04 10:17:52 -07:00
dependabot[bot] 40e8b20257 Bump ch.qos.logback:logback-classic from 1.2.12 to 1.2.13
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.2.12 to 1.2.13.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.2.12...v_1.2.13)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-04 08:51:58 -07:00
Josh Cummings f536b2652f Merge branch '5.8.x' into 6.0.x 2023-12-01 15:45:03 -07:00
Josh Cummings c336ca49fb Update Spring MVC Docs
Closes gh-14220
2023-12-01 12:57:46 -07:00
Josh Cummings c623303ca5 Add Logging
Now if the ServletRegistration API available message is shown, it will
also be accompanied with a startup warning in the logs.

Closes gh-14221
2023-12-01 12:57:46 -07:00
Josh Cummings a98baa7522 Polish ServletRegistration API Deferral
Tomcat uses different ServletContext instances from startup- and request-time.
This commit ensures that if the programmatic API isn't available at startup-time,
then use the ServletContext attached to the HttpServletRequest at runtime.

Issue gh-13794
2023-12-01 12:57:45 -07:00
Steve Riesenberg f25b3fba2f Disable automation to open new milestones on 6.0.x
Note: This change is only applied to 6.0.x and won't
be applied to newer branches.

Issue gh-13195

Closes gh-14203
2023-11-27 12:34:53 -06:00
11 changed files with 82 additions and 557 deletions
@@ -1,23 +0,0 @@
name: Clean build artifacts
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:
GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: |
echo "Running clean build artifacts logic"
output=$(curl -X GET -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts | grep '"id"' | cut -d : -f2 | sed 's/,*$//g')
echo Output is $output
for id in $output; do curl -X DELETE -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts/$id; done;
@@ -1,318 +0,0 @@
name: CI
on:
push:
branches-ignore:
- "dependabot/**"
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
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 }}
COMMIT_OWNER: ${{ github.event.pusher.name }}
COMMIT_SHA: ${{ github.sha }}
STRUCTURE101_LICENSEID: ${{ secrets.STRUCTURE101_LICENSEID }}
ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
permissions:
contents: read
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 }}
samples_branch: ${{ steps.continue.outputs.samples_branch }}
steps:
- uses: actions/checkout@v3
- id: continue
name: Determine if should continue
run: |
# Run jobs if in upstream repository
echo "runjobs=true" >>$GITHUB_OUTPUT
# Extract version from gradle.properties
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
echo "project_version=$version" >>$GITHUB_OUTPUT
samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}')
echo "samples_branch=$samples_branch" >>$GITHUB_OUTPUT
build_jdk_17:
name: Build JDK 17
needs: [prerequisites]
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: 'gradle'
- 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: Build with Gradle
env:
GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }}
GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
run: ./gradlew clean build --continue -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD"
snapshot_tests:
name: Test against snapshots
needs: [prerequisites]
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- name: Snapshot Tests
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 test --refresh-dependencies -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PspringFrameworkVersion='6.0.+' -PreactorVersion='2022.0.+' -PspringDataVersion='2022.0.+' -PlocksDisabled --stacktrace
check_samples:
name: Check Samples project
needs: [prerequisites]
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- name: Check samples project
env:
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
SAMPLES_DIR: ../spring-security-samples
VERSION: ${{ needs.prerequisites.outputs.project_version }}
SAMPLES_BRANCH: ${{ needs.prerequisites.outputs.samples_branch }}
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 publishMavenJavaPublicationToLocalRepository
./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$SAMPLES_BRANCH" -PcloneOutputDirectory="$SAMPLES_DIR"
./gradlew --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$VERSION" :runAllTests
check_tangles:
name: Check for Package Tangles
needs: [ prerequisites ]
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- name: Check for package tangles
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 check s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace
deploy_artifacts:
name: Deploy Artifacts
needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- name: Deploy artifacts
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 publishArtifacts finalizeDeployArtifacts -PossrhUsername="$OSSRH_TOKEN_USERNAME" -PossrhPassword="$OSSRH_TOKEN_PASSWORD" -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" --stacktrace
env:
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_PRIVATE_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_PASSPHRASE }}
OSSRH_TOKEN_USERNAME: ${{ secrets.OSSRH_S01_TOKEN_USERNAME }}
OSSRH_TOKEN_PASSWORD: ${{ secrets.OSSRH_S01_TOKEN_PASSWORD }}
ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
deploy_docs:
name: Deploy Docs
needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- name: Deploy Docs
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 deployDocs -PdeployDocsSshKey="$DOCS_SSH_KEY" -PdeployDocsSshUsername="$DOCS_USERNAME" -PdeployDocsHost="$DOCS_HOST" --stacktrace
env:
DOCS_USERNAME: ${{ secrets.DOCS_USERNAME }}
DOCS_SSH_KEY: ${{ secrets.DOCS_SSH_KEY }}
DOCS_HOST: ${{ secrets.DOCS_HOST }}
deploy_schema:
name: Deploy Schema
needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- name: Deploy Schema
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 deploySchema -PdeployDocsSshKey="$DOCS_SSH_KEY" -PdeployDocsSshUsername="$DOCS_USERNAME" -PdeployDocsHost="$DOCS_HOST" --stacktrace --info
env:
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@v3
with:
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- 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
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@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- 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]
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
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#spring-security-ci'
name: 'CI Notifier'
-33
View File
@@ -1,33 +0,0 @@
name: Deploy Docs
on:
push:
branches-ignore:
- "gh-pages"
- "dependabot/**"
tags: '**'
repository_dispatch:
types: request-build-reference # legacy
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch:
permissions: read-all
jobs:
build:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects'
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: docs-build
fetch-depth: 1
- name: Dispatch (partial build)
if: github.ref_type == 'branch'
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
- name: Dispatch (full build)
if: github.ref_type == 'tag'
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD)
@@ -1,40 +0,0 @@
name: Check Milestone
on:
milestone:
types: [created, opened, edited]
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'"
- name: Validate DueOn
if: env.DUE_ON != ''
run: |
export TOOL_VERSION=0.1.1
wget "https://repo.maven.apache.org/maven2/io/spring/releasetrain/spring-release-train-tools/$TOOL_VERSION/spring-release-train-tools-$TOOL_VERSION.jar"
java -cp "spring-release-train-tools-$TOOL_VERSION.jar" io.spring.releasetrain.CheckMilestoneDueOnMain --dueOn "$DUE_ON" --expectedDayOfWeek MONDAY --expectedMondayCount 3
notify_result:
name: Check for failures
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
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#spring-security-ci'
name: 'CI Notifier'
-21
View File
@@ -1,21 +0,0 @@
name: PR Build
on: pull_request
permissions:
contents: read
jobs:
build:
name: Build
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@v3
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew clean build --continue --scan
-24
View File
@@ -1,24 +0,0 @@
name: Release Scheduler
on:
schedule:
- cron: '15 15 * * MON' # Every Monday at 3:15pm UTC
workflow_dispatch:
permissions: read-all
jobs:
dispatch_scheduled_releases:
name: Dispatch scheduled releases
if: github.repository_owner == 'spring-projects'
strategy:
matrix:
# List of active maintenance branches.
branch: [ main, 6.0.x, 5.8.x, 5.7.x, 5.6.x ]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 1
- name: Dispatch
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run update-scheduled-release-version.yml -r ${{ matrix.branch }}
@@ -1,80 +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@v3
with:
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '17'
distribution: 'temurin'
- 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 "is_due_today=$(cat build/github/milestones/is-due-today)" >>$GITHUB_OUTPUT
- id: check-open-issues
name: Check for open issues
if: steps.check-release-due.outputs.is_due_today == 'true'
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 "is_open_issues=$(cat build/github/milestones/is-open-issues)" >>$GITHUB_OUTPUT
- id: validate-release-state
name: Validate State of Release
if: steps.check-release-due.outputs.is_due_today == 'true' && steps.check-open-issues.outputs.is_open_issues == 'true'
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
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'
@@ -21,17 +21,38 @@ import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
class ArtifactoryPlugin implements Plugin<Project> {
private static final String ARTIFACTORY_URL_NAME = "ARTIFACTORY_URL"
private static final String ARTIFACTORY_SNAPSHOT_REPOSITORY = "ARTIFACTORY_SNAPSHOT_REPOSITORY"
private static final String ARTIFACTORY_MILESTONE_REPOSITORY = "ARTIFACTORY_MILESTONE_REPOSITORY"
private static final String ARTIFACTORY_RELEASE_REPOSITORY = "ARTIFACTORY_RELEASE_REPOSITORY"
private static final String DEFAULT_ARTIFACTORY_URL = "https://repo.spring.io"
private static final String DEFAULT_ARTIFACTORY_SNAPSHOT_REPOSITORY = "libs-snapshot-local"
private static final String DEFAULT_ARTIFACTORY_MILESTONE_REPOSITORY = "libs-milestone-local"
private static final String DEFAULT_ARTIFACTORY_RELEASE_REPOSITORY = "libs-release-local"
@Override
void apply(Project project) {
project.plugins.apply('com.jfrog.artifactory')
String name = Utils.getProjectName(project);
boolean isSnapshot = Utils.isSnapshot(project);
boolean isMilestone = Utils.isMilestone(project);
Map<String, String> env = System.getenv()
String artifactoryUrl = env.getOrDefault(ARTIFACTORY_URL_NAME, DEFAULT_ARTIFACTORY_URL)
String snapshotRepository = env.getOrDefault(ARTIFACTORY_SNAPSHOT_REPOSITORY, DEFAULT_ARTIFACTORY_SNAPSHOT_REPOSITORY)
String milestoneRepository = env.getOrDefault(ARTIFACTORY_MILESTONE_REPOSITORY, DEFAULT_ARTIFACTORY_MILESTONE_REPOSITORY)
String releaseRepository = env.getOrDefault(ARTIFACTORY_RELEASE_REPOSITORY, DEFAULT_ARTIFACTORY_RELEASE_REPOSITORY)
project.artifactory {
contextUrl = 'https://repo.spring.io'
contextUrl = artifactoryUrl
publish {
repository {
repoKey = isSnapshot ? 'libs-snapshot-local' : isMilestone ? 'libs-milestone-local' : 'libs-release-local'
repoKey = isSnapshot ? snapshotRepository : isMilestone ? milestoneRepository : releaseRepository
if(project.hasProperty('artifactoryUsername')) {
username = artifactoryUsername
password = artifactoryPassword
@@ -23,12 +23,14 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.function.Function;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletRegistration;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
@@ -44,7 +46,6 @@ import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
@@ -76,6 +77,8 @@ public abstract class AbstractRequestMatcherRegistry<C> {
AbstractRequestMatcherRegistry.class.getClassLoader());
}
private final Log logger = LogFactory.getLog(getClass());
protected final void setApplicationContext(ApplicationContext context) {
this.context = context;
}
@@ -209,7 +212,12 @@ public abstract class AbstractRequestMatcherRegistry<C> {
matchers.add(resolve(ant, mvc, servletContext));
}
else {
matchers.add(new DeferredRequestMatcher(() -> resolve(ant, mvc, servletContext), mvc, ant));
this.logger
.warn("The ServletRegistration API was not available at startup time. This may be due to a misconfiguration; "
+ "if you are using AbstractSecurityWebApplicationInitializer, please double-check the recommendations outlined in "
+ "https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#abstractsecuritywebapplicationinitializer-with-spring-mvc");
matchers.add(new DeferredRequestMatcher((request) -> resolve(ant, mvc, request.getServletContext()),
mvc, ant));
}
}
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
@@ -466,27 +474,34 @@ public abstract class AbstractRequestMatcherRegistry<C> {
static class DeferredRequestMatcher implements RequestMatcher {
final Supplier<RequestMatcher> requestMatcher;
final Function<HttpServletRequest, RequestMatcher> requestMatcherFactory;
final AtomicReference<String> description = new AtomicReference<>();
DeferredRequestMatcher(Supplier<RequestMatcher> resolver, RequestMatcher... candidates) {
this.requestMatcher = SingletonSupplier.of(() -> {
RequestMatcher matcher = resolver.get();
this.description.set(matcher.toString());
return matcher;
});
volatile RequestMatcher requestMatcher;
DeferredRequestMatcher(Function<HttpServletRequest, RequestMatcher> resolver, RequestMatcher... candidates) {
this.requestMatcherFactory = (request) -> {
if (this.requestMatcher == null) {
synchronized (this) {
if (this.requestMatcher == null) {
this.requestMatcher = resolver.apply(request);
}
}
}
return this.requestMatcher;
};
this.description.set("Deferred " + Arrays.toString(candidates));
}
@Override
public boolean matches(HttpServletRequest request) {
return this.requestMatcher.get().matches(request);
return this.requestMatcherFactory.apply(request).matches(request);
}
@Override
public MatchResult matcher(HttpServletRequest request) {
return this.requestMatcher.get().matcher(request);
return this.requestMatcherFactory.apply(request).matcher(request);
}
@Override
@@ -328,7 +328,7 @@ public class AbstractRequestMatcherRegistryTests {
List<RequestMatcher> requestMatchers = new ArrayList<>();
for (RequestMatcher requestMatcher : wrappedMatchers) {
if (requestMatcher instanceof AbstractRequestMatcherRegistry.DeferredRequestMatcher) {
requestMatchers.add(((DeferredRequestMatcher) requestMatcher).requestMatcher.get());
requestMatchers.add(((DeferredRequestMatcher) requestMatcher).requestMatcher);
}
else {
requestMatchers.add(requestMatcher);
@@ -114,7 +114,7 @@ public class SecurityWebApplicationInitializer
This onlys register the `springSecurityFilterChain` for every URL in your application.
After that, we need to ensure that `WebSecurityConfig` was loaded in our existing `ApplicationInitializer`.
For example, if we use Spring MVC it is added in the `getRootConfigClasses()`:
For example, if we use Spring MVC it is added in the `getServletConfigClasses()`:
[[message-web-application-inititializer-java]]
[source,java]
@@ -123,14 +123,42 @@ public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { WebSecurityConfig.class };
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
}
// ... other overrides ...
}
----
The reason for this is that Spring Security needs to be able to inspect some Spring MVC configuration in order to appropriately configure xref:servlet/authorization/authorize-http-requests.adoc#_request_matchers[underlying request matchers], so they need to be in the same application context.
Placing Spring Security in `getRootConfigClasses` places it into a parent application context that may not be able to find Spring MVC's `HandlerMappingIntrospector`.
==== Configuring for Multiple Spring MVC Dispatchers
If desired, any Spring Security configuration that is unrelated to Spring MVC may be placed in a different configuration class like so:
[source,java]
----
public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { NonWebSecurityConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
}
// ... other overrides ...
}
----
This can be helpful if you have multiple instances of `AbstractAnnotationConfigDispatcherServletInitializer` and don't want to duplicate the general security configuration across both of them.
[[jc-httpsecurity]]
== HttpSecurity