diff --git a/.github/workflows/PR-Demo-Comment-with-react.yml b/.github/workflows/PR-Demo-Comment-with-react.yml index 406568cff..786316365 100644 --- a/.github/workflows/PR-Demo-Comment-with-react.yml +++ b/.github/workflows/PR-Demo-Comment-with-react.yml @@ -156,10 +156,8 @@ jobs: - name: Run Gradle Command run: | if [ "${{ needs.check-comment.outputs.enable_security }}" == "true" ]; then - export DOCKER_ENABLE_SECURITY=true export ADDITIONAL_FEATURES_OFF=false else - export DOCKER_ENABLE_SECURITY=false export ADDITIONAL_FEATURES_OFF=true fi ./gradlew clean build @@ -225,7 +223,6 @@ jobs: - /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/config:/configs:rw - /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "${DOCKER_SECURITY}" # todo: change DOCKER_SECURITY? ADDITIONAL_FEATURES_OFF: "${DOCKER_SECURITY}" SECURITY_ENABLELOGIN: "${LOGIN_SECURITY}" SYSTEM_DEFAULTLOCALE: en-GB diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 198a8d411..797a1bca0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,13 +40,11 @@ jobs: - name: Build with Gradle and no spring security run: ./gradlew clean build env: - DOCKER_ENABLE_SECURITY: false ADDITIONAL_FEATURES_OFF: true - name: Build with Gradle and with spring security run: ./gradlew clean build env: - DOCKER_ENABLE_SECURITY: true ADDITIONAL_FEATURES_OFF: false - name: Upload Test Reports diff --git a/.github/workflows/multiOSReleases.yml b/.github/workflows/multiOSReleases.yml index 8e0ef3837..d10d8e8b6 100644 --- a/.github/workflows/multiOSReleases.yml +++ b/.github/workflows/multiOSReleases.yml @@ -80,7 +80,6 @@ jobs: - name: Generate jar (With Security=${{ matrix.enable_security }}) run: ./gradlew clean createExe env: - DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }} ADDITIONAL_FEATURES_OFF: ${{ matrix.disable_security }} STIRLING_PDF_DESKTOP_UI: false @@ -177,7 +176,6 @@ jobs: - name: Build Installer run: ./gradlew build jpackage -x test --info env: - DOCKER_ENABLE_SECURITY: false ADDITIONAL_FEATURES_OFF: true STIRLING_PDF_DESKTOP_UI: true BROWSER_OPEN: true diff --git a/.github/workflows/push-docker.yml b/.github/workflows/push-docker.yml index 7e9f483f0..210007c72 100644 --- a/.github/workflows/push-docker.yml +++ b/.github/workflows/push-docker.yml @@ -37,7 +37,6 @@ jobs: - name: Run Gradle Command run: ./gradlew clean build env: - DOCKER_ENABLE_SECURITY: false ADDITIONAL_FEATURES_OFF: true STIRLING_PDF_DESKTOP_UI: false diff --git a/.github/workflows/releaseArtifacts.yml b/.github/workflows/releaseArtifacts.yml index 476ae8a9c..09ad89312 100644 --- a/.github/workflows/releaseArtifacts.yml +++ b/.github/workflows/releaseArtifacts.yml @@ -47,7 +47,6 @@ jobs: - name: Generate jar (With Security=${{ matrix.enable_security }}) run: ./gradlew clean createExe env: - DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }} ADDITIONAL_FEATURES_OFF: ${{ matrix.disable_security }} STIRLING_PDF_DESKTOP_UI: false diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index 4c12b819a..5509d74bc 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -33,7 +33,6 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - DOCKER_ENABLE_SECURITY: true ADDITIONAL_FEATURES_OFF: false STIRLING_PDF_DESKTOP_UI: true run: | diff --git a/.github/workflows/testdriver.yml b/.github/workflows/testdriver.yml index a71293e3e..27a8255a4 100644 --- a/.github/workflows/testdriver.yml +++ b/.github/workflows/testdriver.yml @@ -28,7 +28,6 @@ jobs: - name: Build with Gradle run: ./gradlew clean build env: - DOCKER_ENABLE_SECURITY: false ADDITIONAL_FEATURES_OFF: true - name: Set up Docker Buildx @@ -77,7 +76,6 @@ jobs: - /stirling/test-${{ github.sha }}/config:/configs:rw - /stirling/test-${{ github.sha }}/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "false" ADDITIONAL_FEATURES_OFF: "true" SECURITY_ENABLELOGIN: "false" SYSTEM_DEFAULTLOCALE: en-GB diff --git a/DeveloperGuide.md b/DeveloperGuide.md index 675e5b4db..cb4c4827a 100644 --- a/DeveloperGuide.md +++ b/DeveloperGuide.md @@ -55,7 +55,7 @@ Stirling-PDF uses Lombok to reduce boilerplate code. Some IDEs, like Eclipse, do Visit the [Lombok website](https://projectlombok.org/setup/) for installation instructions specific to your IDE. 5. Add environment variable -For local testing, you should generally be testing the full 'Security' version of Stirling-PDF. To do this, you must add the environment flag DOCKER_ENABLE_SECURITY=true or ADDITIONAL_FEATURES_OFF=false to your system and/or IDE build/run step. +For local testing, you should generally be testing the full 'Security' version of Stirling-PDF. To do this, you must add the environment flag ADDITIONAL_FEATURES_OFF=false to your system and/or IDE build/run step. ## 4. Project Structure @@ -141,7 +141,6 @@ services: - /stirling/latest/config:/configs:rw - /stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "true" ADDITIONAL_FEATURES_OFF: "false" SECURITY_ENABLELOGIN: "true" PUID: 1002 @@ -171,7 +170,6 @@ Stirling-PDF uses different Docker images for various configurations. The build 1. Set the security environment variable: ```bash - export DOCKER_ENABLE_SECURITY=false # or true for security-enabled builds export ADDITIONAL_FEATURES_OFF=true # or false for security-enabled builds ``` @@ -198,7 +196,6 @@ Stirling-PDF uses different Docker images for various configurations. The build For the fat version (with security enabled): ```bash - export DOCKER_ENABLE_SECURITY=true export ADDITIONAL_FEATURES_OFF=false docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile.fat . ``` diff --git a/Dockerfile b/Dockerfile index bf302116b..ad8f7c590 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,8 +23,7 @@ LABEL org.opencontainers.image.version="${VERSION_TAG}" LABEL org.opencontainers.image.keywords="PDF, manipulation, merge, split, convert, OCR, watermark" # Set Environment Variables -ENV DOCKER_ENABLE_SECURITY=false \ - ADDITIONAL_FEATURES_OFF=true \ +ENV ADDITIONAL_FEATURES_OFF=true \ VERSION_TAG=$VERSION_TAG \ JAVA_BASE_OPTS="-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 -XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 -XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70" \ JAVA_CUSTOM_OPTS="" \ diff --git a/Dockerfile.fat b/Dockerfile.fat index 203af02da..e742dd43b 100644 --- a/Dockerfile.fat +++ b/Dockerfile.fat @@ -15,9 +15,8 @@ WORKDIR /app # Copy the entire project to the working directory COPY . . -# Build the application with DOCKER_ENABLE_SECURITY=true/ADDITIONAL_FEATURES_OFF=false -RUN DOCKER_ENABLE_SECURITY=true \ - ADDITIONAL_FEATURES_OFF=false \ +# Build the application with ADDITIONAL_FEATURES_OFF=false +RUN ADDITIONAL_FEATURES_OFF=false \ STIRLING_PDF_DESKTOP_UI=false \ ./gradlew clean build -x spotlessApply -x spotlessCheck -x test -x sonarqube @@ -33,8 +32,7 @@ COPY --from=build /app/build/libs/*.jar app.jar ARG VERSION_TAG # Set Environment Variables -ENV DOCKER_ENABLE_SECURITY=false \ - ADDITIONAL_FEATURES_OFF=true \ +ENV ADDITIONAL_FEATURES_OFF=true \ VERSION_TAG=$VERSION_TAG \ JAVA_BASE_OPTS="-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 -XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 -XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70" \ JAVA_CUSTOM_OPTS="" \ diff --git a/Dockerfile.ultra-lite b/Dockerfile.ultra-lite index a30c45d48..3b54091b1 100644 --- a/Dockerfile.ultra-lite +++ b/Dockerfile.ultra-lite @@ -4,8 +4,7 @@ FROM alpine:3.22.0@sha256:8a1f59ffb675680d47db6337b49d22281a139e9d709335b492be02 ARG VERSION_TAG # Set Environment Variables -ENV DOCKER_ENABLE_SECURITY=false \ - ADDITIONAL_FEATURES_OFF=true \ +ENV ADDITIONAL_FEATURES_OFF=true \ HOME=/home/stirlingpdfuser \ VERSION_TAG=$VERSION_TAG \ JAVA_BASE_OPTS="-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 -XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 -XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70" \ diff --git a/LICENSE b/LICENSE index 877663171..62cd6e5cc 100644 --- a/LICENSE +++ b/LICENSE @@ -9,6 +9,13 @@ if that directory exists, is licensed under the license defined in "proprietary/ * Content outside of the above mentioned directories or restrictions above is available under the MIT License as defined below. +Portions of this software are licensed as follows: + +* All content that resides under the "proprietary/" directory of this repository, +if that directory exists, is licensed under the license defined in "proprietary/LICENSE". +* Content outside of the above mentioned directories or restrictions above is +available under the MIT License as defined below. + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/build.gradle b/build.gradle index 87c603617..f813dde11 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ plugins { id "com.diffplug.spotless" version "7.0.4" id "com.github.jk1.dependency-license-report" version "2.9" //id "nebula.lint" version "19.0.3" - id("org.panteleyev.jpackageplugin") version "1.6.1" + id "org.panteleyev.jpackageplugin" version "1.6.1" id "org.sonarqube" version "6.2.0.5505" } @@ -51,12 +51,14 @@ licenseReport { sourceSets { main { java { - if (System.getenv("DOCKER_ENABLE_SECURITY") == "false" || System.getenv("ADDITIONAL_FEATURES_OFF") == "true") { - exclude "stirling/software/proprietary/security/**" + if (System.getenv('DOCKER_ENABLE_SECURITY') == 'false' || System.getenv('ADDITIONAL_FEATURES_OFF') == 'true' + || (project.hasProperty('ADDITIONAL_FEATURES_OFF') + && System.getProperty('ADDITIONAL_FEATURES_OFF') == 'true')) { + exclude 'stirling/software/proprietary/security/**' } - if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") { - exclude "stirling/software/SPDF/UI/impl/**" + if (System.getenv('STIRLING_PDF_DESKTOP_UI') == 'false') { + exclude 'stirling/software/SPDF/UI/impl/**' } } @@ -64,12 +66,14 @@ sourceSets { test { java { - if (System.getenv("DOCKER_ENABLE_SECURITY") == "false" || System.getenv("ADDITIONAL_FEATURES_OFF") == "true") { - exclude "stirling/software/proprietary/security/**" + if (System.getenv('DOCKER_ENABLE_SECURITY') == 'false' || System.getenv('ADDITIONAL_FEATURES_OFF') == 'true' + || (project.hasProperty('ADDITIONAL_FEATURES_OFF') + && System.getProperty('ADDITIONAL_FEATURES_OFF') == 'true')) { + exclude 'stirling/software/proprietary/security/**' } - if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") { - exclude "stirling/software/SPDF/UI/impl/**" + if (System.getenv('STIRLING_PDF_DESKTOP_UI') == 'false') { + exclude 'stirling/software/SPDF/UI/impl/**' } } } @@ -281,18 +285,18 @@ tasks.register('downloadTempJre') { def jreArchive = new File(tmpDir, 'jre.tar.gz') def jreDir = new File(tmpDir, 'jre') - println "🔽 Downloading JRE to $jreArchive..." + println "Downloading JRE to $jreArchive..." jreArchive.withOutputStream { out -> new URI(jreUrl).toURL().withInputStream { from -> out << from } } - println "📦 Extracting JRE to $jreDir..." + println "Extracting JRE to $jreDir..." jreDir.mkdirs() providers.exec { commandLine 'tar', '-xzf', jreArchive.absolutePath, '-C', jreDir.absolutePath, '--strip-components=1' }.result.get() - println "✅ JRE ready at: $jreDir" + println "JRE ready at: $jreDir" ext.tempJrePath = jreDir.absolutePath project.ext.tempJrePath = jreDir.absolutePath } catch (Exception e) { @@ -427,7 +431,7 @@ dependencies { implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1' implementation 'org.snakeyaml:snakeyaml-engine:2.9' - if (System.getenv("DOCKER_ENABLE_SECURITY") != "false" || System.getenv("ADDITIONAL_FEATURES_OFF") == "false") { + if (System.getenv("DOCKER_ENABLE_SECURITY") != "false" && System.getenv("ADDITIONAL_FEATURES_OFF") != "true") { implementation project(':proprietary') } diff --git a/common/gradle/wrapper/gradle-wrapper.properties b/common/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..f7664bccf --- /dev/null +++ b/common/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/common/gradlew b/common/gradlew new file mode 100755 index 000000000..23d15a936 --- /dev/null +++ b/common/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/common/gradlew.bat b/common/gradlew.bat new file mode 100644 index 000000000..db3a6ac20 --- /dev/null +++ b/common/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/common/src/main/java/stirling/software/common/configuration/AppConfig.java b/common/src/main/java/stirling/software/common/configuration/AppConfig.java index f6b8b2d45..27109b16f 100644 --- a/common/src/main/java/stirling/software/common/configuration/AppConfig.java +++ b/common/src/main/java/stirling/software/common/configuration/AppConfig.java @@ -148,10 +148,16 @@ public class AppConfig { } @Bean(name = "activeSecurity") - @ConditionalOnClass( - name = "stirling.software.proprietary.security.configuration.SecurityConfiguration") public boolean activeSecurity() { - return true; + String additionalFeaturesOff = env.getProperty("ADDITIONAL_FEATURES_OFF"); + + if (additionalFeaturesOff != null) { + // ADDITIONAL_FEATURES_OFF=true means security OFF, so return false + // ADDITIONAL_FEATURES_OFF=false means security ON, so return true + return !Boolean.parseBoolean(additionalFeaturesOff); + } + + return env.getProperty("DOCKER_ENABLE_SECURITY", Boolean.class, true); } @Bean(name = "missingActiveSecurity") diff --git a/exampleYmlFiles/docker-compose-latest-fat-endpoints-disabled.yml b/exampleYmlFiles/docker-compose-latest-fat-endpoints-disabled.yml index 63b0a7467..4f3b25948 100644 --- a/exampleYmlFiles/docker-compose-latest-fat-endpoints-disabled.yml +++ b/exampleYmlFiles/docker-compose-latest-fat-endpoints-disabled.yml @@ -20,7 +20,6 @@ services: - ./stirling/latest/logs:/logs:rw - ../testing/allEndpointsRemovedSettings.yml:/configs/settings.yml:rw environment: - DOCKER_ENABLE_SECURITY: "true" ADDITIONAL_FEATURES_OFF: "false" SECURITY_ENABLELOGIN: "false" PUID: 1002 diff --git a/exampleYmlFiles/docker-compose-latest-fat-security-postgres.yml b/exampleYmlFiles/docker-compose-latest-fat-security-postgres.yml index 318065e05..f38ed84e2 100644 --- a/exampleYmlFiles/docker-compose-latest-fat-security-postgres.yml +++ b/exampleYmlFiles/docker-compose-latest-fat-security-postgres.yml @@ -20,7 +20,6 @@ services: - ./stirling/latest/config:/configs:rw - ./stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "true" ADDITIONAL_FEATURES_OFF: "false" SECURITY_ENABLELOGIN: "false" PUID: 1002 diff --git a/exampleYmlFiles/docker-compose-latest-fat-security.yml b/exampleYmlFiles/docker-compose-latest-fat-security.yml index 8d9ebeff4..88441ee9a 100644 --- a/exampleYmlFiles/docker-compose-latest-fat-security.yml +++ b/exampleYmlFiles/docker-compose-latest-fat-security.yml @@ -18,7 +18,6 @@ services: - ./stirling/latest/config:/configs:rw - ./stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "true" ADDITIONAL_FEATURES_OFF: "false" SECURITY_ENABLELOGIN: "false" PUID: 1002 diff --git a/exampleYmlFiles/docker-compose-latest-security-with-sso.yml b/exampleYmlFiles/docker-compose-latest-security-with-sso.yml index 36cbfe868..947ddc447 100644 --- a/exampleYmlFiles/docker-compose-latest-security-with-sso.yml +++ b/exampleYmlFiles/docker-compose-latest-security-with-sso.yml @@ -18,7 +18,6 @@ services: - /stirling/latest/config:/configs:rw - /stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "true" ADDITIONAL_FEATURES_OFF: "false" SECURITY_ENABLELOGIN: "true" SECURITY_OAUTH2_ENABLED: "true" diff --git a/exampleYmlFiles/docker-compose-latest-security.yml b/exampleYmlFiles/docker-compose-latest-security.yml index d6d90bf0a..fa8d76888 100644 --- a/exampleYmlFiles/docker-compose-latest-security.yml +++ b/exampleYmlFiles/docker-compose-latest-security.yml @@ -18,7 +18,6 @@ services: - ./stirling/latest/config:/configs:rw - ./stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "true" ADDITIONAL_FEATURES_OFF: "false" SECURITY_ENABLELOGIN: "true" PUID: 1002 diff --git a/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml b/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml index b3cb57cd1..434bbcd61 100644 --- a/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml +++ b/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml @@ -18,7 +18,6 @@ services: - /stirling/latest/config:/configs:rw - /stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "true" ADDITIONAL_FEATURES_OFF: "false" SECURITY_ENABLELOGIN: "true" SYSTEM_DEFAULTLOCALE: en-US diff --git a/exampleYmlFiles/docker-compose-latest-ultra-lite.yml b/exampleYmlFiles/docker-compose-latest-ultra-lite.yml index f6c1b703a..484acf269 100644 --- a/exampleYmlFiles/docker-compose-latest-ultra-lite.yml +++ b/exampleYmlFiles/docker-compose-latest-ultra-lite.yml @@ -17,7 +17,6 @@ services: - /stirling/latest/config:/configs:rw - /stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "false" ADDITIONAL_FEATURES_OFF: "true" SECURITY_ENABLELOGIN: "false" SYSTEM_DEFAULTLOCALE: en-US diff --git a/exampleYmlFiles/docker-compose-latest.yml b/exampleYmlFiles/docker-compose-latest.yml index 3a296b84a..46cfe3553 100644 --- a/exampleYmlFiles/docker-compose-latest.yml +++ b/exampleYmlFiles/docker-compose-latest.yml @@ -18,7 +18,6 @@ services: - /stirling/latest/config:/configs:rw - /stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "false" ADDITIONAL_FEATURES_OFF: "true" SECURITY_ENABLELOGIN: "false" LANGS: "en_GB,en_US,ar_AR,de_DE,fr_FR,es_ES,zh_CN,zh_TW,ca_CA,it_IT,sv_SE,pl_PL,ro_RO,ko_KR,pt_BR,ru_RU,el_GR,hi_IN,hu_HU,tr_TR,id_ID" diff --git a/exampleYmlFiles/test_cicd.yml b/exampleYmlFiles/test_cicd.yml index f92c80d8f..c76471bd8 100644 --- a/exampleYmlFiles/test_cicd.yml +++ b/exampleYmlFiles/test_cicd.yml @@ -18,7 +18,6 @@ services: - /stirling/latest/config:/configs:rw - /stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "true" ADDITIONAL_FEATURES_OFF: "false" SECURITY_ENABLELOGIN: "true" PUID: 1002 diff --git a/proprietary/gradle/wrapper/gradle-wrapper.properties b/proprietary/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..f7664bccf --- /dev/null +++ b/proprietary/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/proprietary/gradlew b/proprietary/gradlew new file mode 100755 index 000000000..23d15a936 --- /dev/null +++ b/proprietary/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/proprietary/gradlew.bat b/proprietary/gradlew.bat new file mode 100644 index 000000000..db3a6ac20 --- /dev/null +++ b/proprietary/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationFailureHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationFailureHandler.java index ee726b9fb..47ad7671c 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationFailureHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationFailureHandler.java @@ -1,11 +1,8 @@ package stirling.software.proprietary.security; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Optional; -import lombok.extern.slf4j.Slf4j; + import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.InternalAuthenticationServiceException; @@ -13,6 +10,13 @@ import org.springframework.security.authentication.LockedException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.security.model.User; import stirling.software.proprietary.security.service.LoginAttemptService; import stirling.software.proprietary.security.service.UserService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationSuccessHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationSuccessHandler.java index b9379ec74..8b6ea1dec 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationSuccessHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationSuccessHandler.java @@ -1,14 +1,18 @@ package stirling.software.proprietary.security; +import java.io.IOException; + +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.security.web.savedrequest.SavedRequest; + import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; -import java.io.IOException; + import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; -import org.springframework.security.web.savedrequest.SavedRequest; + import stirling.software.common.util.RequestUriUtils; import stirling.software.proprietary.security.service.LoginAttemptService; import stirling.software.proprietary.security.service.UserService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/CustomLogoutSuccessHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/CustomLogoutSuccessHandler.java index 244e16da0..44046eb71 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/CustomLogoutSuccessHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/CustomLogoutSuccessHandler.java @@ -1,22 +1,27 @@ package stirling.software.proprietary.security; -import com.coveo.saml.SamlClient; -import com.coveo.saml.SamlException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.util.ArrayList; import java.util.List; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.springframework.core.io.Resource; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; + +import com.coveo.saml.SamlClient; +import com.coveo.saml.SamlException; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.AppConfig; import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; @@ -171,8 +176,7 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler { private SamlClient getSamlClient( String registrationId, SAML2 samlConf, List certificates) throws SamlException { - String serverUrl = - appConfig.getBaseUrl() + ":" + appConfig.getServerPort(); + String serverUrl = appConfig.getBaseUrl() + ":" + appConfig.getServerPort(); String relyingPartyIdentifier = serverUrl + "/saml2/service-provider-metadata/" + registrationId; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java b/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java index 1353f2151..6568ac3b0 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java @@ -1,14 +1,18 @@ package stirling.software.proprietary.security; -import jakarta.annotation.PostConstruct; import java.sql.SQLException; import java.util.UUID; + +import org.springframework.stereotype.Component; + +import jakarta.annotation.PostConstruct; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; + import stirling.software.common.model.ApplicationProperties; -import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.common.model.enumeration.Role; +import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.proprietary.security.service.DatabaseServiceInterface; import stirling.software.proprietary.security.service.UserService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/RateLimitResetScheduler.java b/proprietary/src/main/java/stirling/software/proprietary/security/RateLimitResetScheduler.java index 4faeb9041..25b3c5096 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/RateLimitResetScheduler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/RateLimitResetScheduler.java @@ -1,8 +1,10 @@ package stirling.software.proprietary.security; -import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + import stirling.software.proprietary.security.filter.IPRateLimitingFilter; @Component diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/DatabaseConfig.java b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/DatabaseConfig.java index 5507580a4..2feab9a46 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/DatabaseConfig.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/DatabaseConfig.java @@ -1,8 +1,7 @@ package stirling.software.proprietary.security.configuration; import javax.sql.DataSource; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.domain.EntityScan; @@ -11,6 +10,10 @@ import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.exception.UnsupportedProviderException; @@ -65,15 +68,17 @@ public class DatabaseConfig { private DataSource useDefaultDataSource(DataSourceBuilder dataSourceBuilder) { log.info("Using default H2 database"); - dataSourceBuilder.url(DATASOURCE_DEFAULT_URL) - .driverClassName(DatabaseDriver.H2.getDriverClassName()) - .username(DEFAULT_USERNAME); + dataSourceBuilder + .url(DATASOURCE_DEFAULT_URL) + .driverClassName(DatabaseDriver.H2.getDriverClassName()) + .username(DEFAULT_USERNAME); return dataSourceBuilder.build(); } @ConditionalOnBooleanProperty(name = "premium.enabled") - private DataSource useCustomDataSource(DataSourceBuilder dataSourceBuilder) throws UnsupportedProviderException { + private DataSource useCustomDataSource(DataSourceBuilder dataSourceBuilder) + throws UnsupportedProviderException { log.info("Using custom database configuration"); if (!datasource.getCustomDatabaseUrl().isBlank()) { @@ -85,11 +90,11 @@ public class DatabaseConfig { } else { dataSourceBuilder.driverClassName(getDriverClassName(datasource.getType())); dataSourceBuilder.url( - generateCustomDataSourceUrl( - datasource.getType(), - datasource.getHostName(), - datasource.getPort(), - datasource.getName())); + generateCustomDataSourceUrl( + datasource.getType(), + datasource.getHostName(), + datasource.getPort(), + datasource.getName())); } dataSourceBuilder.username(datasource.getUsername()); dataSourceBuilder.password(datasource.getPassword()); diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java index 82d794d6e..c9b6e9d77 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java @@ -10,6 +10,7 @@ import org.springframework.mail.javamail.JavaMailSenderImpl; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; /** diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java index cec19214a..b49e19c08 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java @@ -1,7 +1,7 @@ package stirling.software.proprietary.security.configuration; import java.util.Optional; -import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; @@ -26,6 +26,9 @@ import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; import org.springframework.security.web.savedrequest.NullRequestCache; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.AppConfig; import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.security.CustomAuthenticationFailureHandler; @@ -71,22 +74,22 @@ public class SecurityConfiguration { private final OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver; public SecurityConfiguration( - PersistentLoginRepository persistentLoginRepository, - CustomUserDetailsService userDetailsService, - @Lazy UserService userService, - @Qualifier("loginEnabled") boolean loginEnabledValue, - @Qualifier("runningProOrHigher") boolean runningProOrHigher, - AppConfig appConfig, - ApplicationProperties applicationProperties, - UserAuthenticationFilter userAuthenticationFilter, - LoginAttemptService loginAttemptService, - FirstLoginFilter firstLoginFilter, - SessionPersistentRegistry sessionRegistry, - @Autowired(required = false) GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper, - @Autowired(required = false) - RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations, - @Autowired(required = false) - OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver) { + PersistentLoginRepository persistentLoginRepository, + CustomUserDetailsService userDetailsService, + @Lazy UserService userService, + @Qualifier("loginEnabled") boolean loginEnabledValue, + @Qualifier("runningProOrHigher") boolean runningProOrHigher, + AppConfig appConfig, + ApplicationProperties applicationProperties, + UserAuthenticationFilter userAuthenticationFilter, + LoginAttemptService loginAttemptService, + FirstLoginFilter firstLoginFilter, + SessionPersistentRegistry sessionRegistry, + @Autowired(required = false) GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper, + @Autowired(required = false) + RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations, + @Autowired(required = false) + OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver) { this.userDetailsService = userDetailsService; this.userService = userService; this.loginEnabledValue = loginEnabledValue; @@ -116,180 +119,183 @@ public class SecurityConfiguration { if (loginEnabledValue) { http.addFilterBefore( - userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); if (!applicationProperties.getSecurity().getCsrfDisabled()) { CookieCsrfTokenRepository cookieRepo = - CookieCsrfTokenRepository.withHttpOnlyFalse(); + CookieCsrfTokenRepository.withHttpOnlyFalse(); CsrfTokenRequestAttributeHandler requestHandler = - new CsrfTokenRequestAttributeHandler(); + new CsrfTokenRequestAttributeHandler(); requestHandler.setCsrfRequestAttributeName(null); http.csrf( - csrf -> - csrf.ignoringRequestMatchers( - request -> { - String apiKey = request.getHeader("X-API-KEY"); - // If there's no API key, don't ignore CSRF - // (return false) - if (apiKey == null || apiKey.trim().isEmpty()) { - return false; - } - // Validate API key using existing UserService - try { - Optional user = - userService.getUserByApiKey(apiKey); - // If API key is valid, ignore CSRF (return - // true) - // If API key is invalid, don't ignore CSRF - // (return false) - return user.isPresent(); - } catch (Exception e) { - // If there's any error validating the API - // key, don't ignore CSRF - return false; - } - }) - .csrfTokenRepository(cookieRepo) - .csrfTokenRequestHandler(requestHandler)); + csrf -> + csrf.ignoringRequestMatchers( + request -> { + String apiKey = request.getHeader("X-API-KEY"); + // If there's no API key, don't ignore CSRF + // (return false) + if (apiKey == null || apiKey.trim().isEmpty()) { + return false; + } + // Validate API key using existing UserService + try { + Optional user = + userService.getUserByApiKey(apiKey); + // If API key is valid, ignore CSRF (return + // true) + // If API key is invalid, don't ignore CSRF + // (return false) + return user.isPresent(); + } catch (Exception e) { + // If there's any error validating the API + // key, don't ignore CSRF + return false; + } + }) + .csrfTokenRepository(cookieRepo) + .csrfTokenRequestHandler(requestHandler)); } http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class); http.sessionManagement( - sessionManagement -> - sessionManagement - .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) - .maximumSessions(10) - .maxSessionsPreventsLogin(false) - .sessionRegistry(sessionRegistry) - .expiredUrl("/login?logout=true")); + sessionManagement -> + sessionManagement + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) + .maximumSessions(10) + .maxSessionsPreventsLogin(false) + .sessionRegistry(sessionRegistry) + .expiredUrl("/login?logout=true")); http.authenticationProvider(daoAuthenticationProvider()); http.requestCache(requestCache -> requestCache.requestCache(new NullRequestCache())); http.logout( - logout -> - logout.logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher("/logout")) - .logoutSuccessHandler( - new CustomLogoutSuccessHandler(applicationProperties, appConfig)) - .clearAuthentication(true) - .invalidateHttpSession(true) - .deleteCookies("JSESSIONID", "remember-me")); + logout -> + logout.logoutRequestMatcher( + PathPatternRequestMatcher.withDefaults() + .matcher("/logout")) + .logoutSuccessHandler( + new CustomLogoutSuccessHandler( + applicationProperties, appConfig)) + .clearAuthentication(true) + .invalidateHttpSession(true) + .deleteCookies("JSESSIONID", "remember-me")); http.rememberMe( - rememberMeConfigurer -> // Use the configurator directly + rememberMeConfigurer -> // Use the configurator directly rememberMeConfigurer - .tokenRepository(persistentTokenRepository()) - .tokenValiditySeconds( // 14 days - 14 * 24 * 60 * 60) - .userDetailsService( // Your existing UserDetailsService - userDetailsService) - .useSecureCookie( // Enable secure cookie - true) - .rememberMeParameter( // Form parameter name - "remember-me") - .rememberMeCookieName( // Cookie name - "remember-me") - .alwaysRemember(false)); + .tokenRepository(persistentTokenRepository()) + .tokenValiditySeconds( // 14 days + 14 * 24 * 60 * 60) + .userDetailsService( // Your existing UserDetailsService + userDetailsService) + .useSecureCookie( // Enable secure cookie + true) + .rememberMeParameter( // Form parameter name + "remember-me") + .rememberMeCookieName( // Cookie name + "remember-me") + .alwaysRemember(false)); http.authorizeHttpRequests( - authz -> - authz.requestMatchers( - req -> { - String uri = req.getRequestURI(); - String contextPath = req.getContextPath(); - // Remove the context path from the URI - String trimmedUri = - uri.startsWith(contextPath) - ? uri.substring( - contextPath.length()) - : uri; - return trimmedUri.startsWith("/login") - || trimmedUri.startsWith("/oauth") - || trimmedUri.startsWith("/saml2") - || trimmedUri.endsWith(".svg") - || trimmedUri.startsWith("/register") - || trimmedUri.startsWith("/error") - || trimmedUri.startsWith("/images/") - || trimmedUri.startsWith("/public/") - || trimmedUri.startsWith("/css/") - || trimmedUri.startsWith("/fonts/") - || trimmedUri.startsWith("/js/") - || trimmedUri.startsWith( - "/api/v1/info/status"); - }) - .permitAll() - .anyRequest() - .authenticated()); + authz -> + authz.requestMatchers( + req -> { + String uri = req.getRequestURI(); + String contextPath = req.getContextPath(); + // Remove the context path from the URI + String trimmedUri = + uri.startsWith(contextPath) + ? uri.substring( + contextPath.length()) + : uri; + return trimmedUri.startsWith("/login") + || trimmedUri.startsWith("/oauth") + || trimmedUri.startsWith("/saml2") + || trimmedUri.endsWith(".svg") + || trimmedUri.startsWith("/register") + || trimmedUri.startsWith("/error") + || trimmedUri.startsWith("/images/") + || trimmedUri.startsWith("/public/") + || trimmedUri.startsWith("/css/") + || trimmedUri.startsWith("/fonts/") + || trimmedUri.startsWith("/js/") + || trimmedUri.startsWith( + "/api/v1/info/status"); + }) + .permitAll() + .anyRequest() + .authenticated()); // Handle User/Password Logins if (applicationProperties.getSecurity().isUserPass()) { http.formLogin( - formLogin -> - formLogin - .loginPage("/login") - .successHandler( - new CustomAuthenticationSuccessHandler( - loginAttemptService, userService)) - .failureHandler( - new CustomAuthenticationFailureHandler( - loginAttemptService, userService)) - .defaultSuccessUrl("/") - .permitAll()); + formLogin -> + formLogin + .loginPage("/login") + .successHandler( + new CustomAuthenticationSuccessHandler( + loginAttemptService, userService)) + .failureHandler( + new CustomAuthenticationFailureHandler( + loginAttemptService, userService)) + .defaultSuccessUrl("/") + .permitAll()); } // Handle OAUTH2 Logins if (applicationProperties.getSecurity().isOauth2Active()) { http.oauth2Login( - oauth2 -> - oauth2.loginPage("/oauth2") - /* - This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database. - If user exists, login proceeds as usual. If user does not exist, then it is auto-created but only if 'OAUTH2AutoCreateUser' - is set as true, else login fails with an error message advising the same. - */ - .successHandler( - new CustomOAuth2AuthenticationSuccessHandler( - loginAttemptService, - applicationProperties, - userService)) - .failureHandler( - new CustomOAuth2AuthenticationFailureHandler()) - . // Add existing Authorities from the database - userInfoEndpoint( - userInfoEndpoint -> - userInfoEndpoint - .oidcUserService( - new CustomOAuth2UserService( - applicationProperties, - userService, - loginAttemptService)) - .userAuthoritiesMapper( - oAuth2userAuthoritiesMapper)) - .permitAll()); + oauth2 -> + oauth2.loginPage("/oauth2") + /* + This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database. + If user exists, login proceeds as usual. If user does not exist, then it is auto-created but only if 'OAUTH2AutoCreateUser' + is set as true, else login fails with an error message advising the same. + */ + .successHandler( + new CustomOAuth2AuthenticationSuccessHandler( + loginAttemptService, + applicationProperties, + userService)) + .failureHandler( + new CustomOAuth2AuthenticationFailureHandler()) + . // Add existing Authorities from the database + userInfoEndpoint( + userInfoEndpoint -> + userInfoEndpoint + .oidcUserService( + new CustomOAuth2UserService( + applicationProperties, + userService, + loginAttemptService)) + .userAuthoritiesMapper( + oAuth2userAuthoritiesMapper)) + .permitAll()); } // Handle SAML if (applicationProperties.getSecurity().isSaml2Active() && runningProOrHigher) { // Configure the authentication provider OpenSaml4AuthenticationProvider authenticationProvider = - new OpenSaml4AuthenticationProvider(); + new OpenSaml4AuthenticationProvider(); authenticationProvider.setResponseAuthenticationConverter( - new CustomSaml2ResponseAuthenticationConverter(userService)); + new CustomSaml2ResponseAuthenticationConverter(userService)); http.authenticationProvider(authenticationProvider) - .saml2Login( - saml2 -> { - try { - saml2.loginPage("/saml2") - .relyingPartyRegistrationRepository( - saml2RelyingPartyRegistrations) - .authenticationManager( - new ProviderManager(authenticationProvider)) - .successHandler( - new CustomSaml2AuthenticationSuccessHandler( - loginAttemptService, - applicationProperties, - userService)) - .failureHandler( - new CustomSaml2AuthenticationFailureHandler()) - .authenticationRequestResolver( - saml2AuthenticationRequestResolver); - } catch (Exception e) { - log.error("Error configuring SAML 2 login", e); - throw new RuntimeException(e); - } - }); + .saml2Login( + saml2 -> { + try { + saml2.loginPage("/saml2") + .relyingPartyRegistrationRepository( + saml2RelyingPartyRegistrations) + .authenticationManager( + new ProviderManager(authenticationProvider)) + .successHandler( + new CustomSaml2AuthenticationSuccessHandler( + loginAttemptService, + applicationProperties, + userService)) + .failureHandler( + new CustomSaml2AuthenticationFailureHandler()) + .authenticationRequestResolver( + saml2AuthenticationRequestResolver); + } catch (Exception e) { + log.error("Error configuring SAML 2 login", e); + throw new RuntimeException(e); + } + }); } } else { log.debug("Login is not enabled."); diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/DatabaseController.java b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/DatabaseController.java index bbc84821f..dec64c46f 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/DatabaseController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/DatabaseController.java @@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.security.database.H2SQLCondition; import stirling.software.proprietary.security.service.DatabaseService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java index dec5905ba..e1abb6989 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java @@ -29,11 +29,11 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import stirling.software.proprietary.security.model.AuthenticationType; -import stirling.software.common.model.enumeration.Role; -import stirling.software.proprietary.security.model.User; import stirling.software.common.model.ApplicationProperties; +import stirling.software.common.model.enumeration.Role; import stirling.software.common.model.exception.UnsupportedProviderException; +import stirling.software.proprietary.security.model.AuthenticationType; +import stirling.software.proprietary.security.model.User; import stirling.software.proprietary.security.model.api.user.UsernameAndPass; import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal; import stirling.software.proprietary.security.service.UserService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/AccountWebController.java b/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/AccountWebController.java index 311f81a4f..bdf1df32e 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/AccountWebController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/AccountWebController.java @@ -29,12 +29,12 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; -import stirling.software.common.model.enumeration.Role; import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2.Client; import stirling.software.common.model.ApplicationProperties.Security.SAML2; +import stirling.software.common.model.enumeration.Role; import stirling.software.common.model.oauth2.GitHubProvider; import stirling.software.common.model.oauth2.GoogleProvider; import stirling.software.common.model.oauth2.KeycloakProvider; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/ScheduledTasks.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/ScheduledTasks.java index 835dc1917..6821414aa 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/ScheduledTasks.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/ScheduledTasks.java @@ -1,10 +1,13 @@ package stirling.software.proprietary.security.database; import java.sql.SQLException; -import lombok.RequiredArgsConstructor; + import org.springframework.context.annotation.Conditional; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.proprietary.security.service.DatabaseServiceInterface; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/AuthorityRepository.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/AuthorityRepository.java index a7773d859..e8d74ec01 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/AuthorityRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/AuthorityRepository.java @@ -4,6 +4,7 @@ import java.util.Set; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; + import stirling.software.proprietary.security.model.Authority; @Repository diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/JPATokenRepositoryImpl.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/JPATokenRepositoryImpl.java index b98a8094f..ec7a0078b 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/JPATokenRepositoryImpl.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/JPATokenRepositoryImpl.java @@ -5,6 +5,7 @@ import java.util.Date; import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import org.springframework.transaction.annotation.Transactional; + import stirling.software.proprietary.security.model.PersistentLogin; public class JPATokenRepositoryImpl implements PersistentTokenRepository { diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/PersistentLoginRepository.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/PersistentLoginRepository.java index a9ddf8a37..2ab956676 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/PersistentLoginRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/PersistentLoginRepository.java @@ -2,6 +2,7 @@ package stirling.software.proprietary.security.database.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; + import stirling.software.proprietary.security.model.PersistentLogin; @Repository diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/SessionRepository.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/SessionRepository.java index b7a7d7a84..78206b259 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/SessionRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/SessionRepository.java @@ -1,13 +1,16 @@ package stirling.software.proprietary.security.database.repository; -import jakarta.transaction.Transactional; import java.util.Date; import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; + +import jakarta.transaction.Transactional; + import stirling.software.proprietary.security.model.SessionEntity; @Repository diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/UserRepository.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/UserRepository.java index dcf84ee19..2a8d42096 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/UserRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/UserRepository.java @@ -7,6 +7,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; + import stirling.software.proprietary.security.model.User; @Repository diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/FirstLoginFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/FirstLoginFilter.java index a96e6e769..3bae72195 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/FirstLoginFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/FirstLoginFilter.java @@ -1,20 +1,24 @@ package stirling.software.proprietary.security.filter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Optional; + +import org.springframework.context.annotation.Lazy; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Optional; + import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Lazy; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; + import stirling.software.common.util.RequestUriUtils; import stirling.software.proprietary.security.model.User; import stirling.software.proprietary.security.service.UserService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/IPRateLimitingFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/IPRateLimitingFilter.java index ebc0f949e..028768c08 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/IPRateLimitingFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/IPRateLimitingFilter.java @@ -1,15 +1,18 @@ package stirling.software.proprietary.security.filter; +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; + import lombok.RequiredArgsConstructor; + import stirling.software.common.util.RequestUriUtils; @RequiredArgsConstructor diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java index de97ec785..e9addd239 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java @@ -1,13 +1,9 @@ package stirling.software.proprietary.security.filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; import java.util.Optional; -import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpStatus; @@ -20,6 +16,14 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.SAML2; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserBasedRateLimitingFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserBasedRateLimitingFilter.java index 31db979b0..4d1d7bbed 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserBasedRateLimitingFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserBasedRateLimitingFilter.java @@ -1,17 +1,10 @@ package stirling.software.proprietary.security.filter; -import io.github.bucket4j.Bandwidth; -import io.github.bucket4j.Bucket; -import io.github.bucket4j.ConsumptionProbe; -import io.github.pixee.security.Newlines; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.time.Duration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; @@ -20,6 +13,17 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; + +import io.github.bucket4j.Bandwidth; +import io.github.bucket4j.Bucket; +import io.github.bucket4j.ConsumptionProbe; +import io.github.pixee.security.Newlines; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + import stirling.software.common.model.enumeration.Role; @Component diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/User.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/User.java index 6dc32a85d..b364f3738 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/User.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/User.java @@ -14,6 +14,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; + import stirling.software.common.model.enumeration.Role; @Entity diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/Email.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/Email.java index 8fe3cebe6..4e9421aba 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/Email.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/Email.java @@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; + import stirling.software.common.model.api.GeneralFile; @Data diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationFailureHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationFailureHandler.java index 92b053b8a..7175a5b5d 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationFailureHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationFailureHandler.java @@ -1,10 +1,7 @@ package stirling.software.proprietary.security.oauth2; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import lombok.extern.slf4j.Slf4j; + import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.LockedException; @@ -13,6 +10,12 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; + @Slf4j public class CustomOAuth2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java index 1c4d04e55..71bd42a85 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java @@ -1,18 +1,22 @@ package stirling.software.proprietary.security.oauth2; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.HttpSession; import java.io.IOException; import java.sql.SQLException; -import lombok.RequiredArgsConstructor; + import org.springframework.security.authentication.LockedException; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.SavedRequest; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +import lombok.RequiredArgsConstructor; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.exception.UnsupportedProviderException; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/OAuth2Configuration.java b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/OAuth2Configuration.java index cb2771cc0..6516cc7d7 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/OAuth2Configuration.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/OAuth2Configuration.java @@ -1,13 +1,16 @@ package stirling.software.proprietary.security.oauth2; +import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE; +import static stirling.software.common.util.ProviderUtils.validateProvider; +import static stirling.software.common.util.ValidationUtils.isStringEmpty; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; -import lombok.extern.slf4j.Slf4j; + import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -20,20 +23,20 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio import org.springframework.security.oauth2.client.registration.ClientRegistrations; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2.Client; import stirling.software.common.model.enumeration.UsernameAttribute; -import stirling.software.proprietary.security.model.exception.NoProviderFoundException; import stirling.software.common.model.oauth2.GitHubProvider; import stirling.software.common.model.oauth2.GoogleProvider; import stirling.software.common.model.oauth2.KeycloakProvider; import stirling.software.common.model.oauth2.Provider; import stirling.software.proprietary.security.model.User; +import stirling.software.proprietary.security.model.exception.NoProviderFoundException; import stirling.software.proprietary.security.service.UserService; -import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE; -import static stirling.software.common.util.ProviderUtils.validateProvider; -import static stirling.software.common.util.ValidationUtils.isStringEmpty; @Slf4j @Configuration diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CertificateUtils.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CertificateUtils.java index c2957e241..fff03fd4f 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CertificateUtils.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CertificateUtils.java @@ -6,6 +6,7 @@ import java.nio.charset.StandardCharsets; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; + import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticatedPrincipal.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticatedPrincipal.java index 055ac8f4e..a39a39092 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticatedPrincipal.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticatedPrincipal.java @@ -3,6 +3,7 @@ package stirling.software.proprietary.security.saml2; import java.io.Serializable; import java.util.List; import java.util.Map; + import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationFailureHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationFailureHandler.java index a7e663aac..7bf0c3a3b 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationFailureHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationFailureHandler.java @@ -1,9 +1,7 @@ package stirling.software.proprietary.security.saml2; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import lombok.extern.slf4j.Slf4j; + import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.security.authentication.ProviderNotFoundException; import org.springframework.security.core.AuthenticationException; @@ -11,6 +9,11 @@ import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; + @Slf4j @ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true") public class CustomSaml2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationSuccessHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationSuccessHandler.java index 47391e4d0..2170a9632 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationSuccessHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationSuccessHandler.java @@ -1,17 +1,21 @@ package stirling.software.proprietary.security.saml2; +import java.io.IOException; +import java.sql.SQLException; + +import org.springframework.security.authentication.LockedException; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.security.web.savedrequest.SavedRequest; + import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; -import java.io.IOException; -import java.sql.SQLException; + import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.authentication.LockedException; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; -import org.springframework.security.web.savedrequest.SavedRequest; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.SAML2; import stirling.software.common.model.exception.UnsupportedProviderException; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2ResponseAuthenticationConverter.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2ResponseAuthenticationConverter.java index d1c24b420..e8326c1e3 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2ResponseAuthenticationConverter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2ResponseAuthenticationConverter.java @@ -5,8 +5,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.opensaml.core.xml.XMLObject; import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.Attribute; @@ -17,6 +16,10 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.security.model.User; import stirling.software.proprietary.security.service.UserService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java index 836419ea0..233bcaadd 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java @@ -1,11 +1,9 @@ package stirling.software.proprietary.security.saml2; -import jakarta.servlet.http.HttpServletRequest; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.UUID; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.opensaml.saml.saml2.core.AuthnRequest; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -21,6 +19,12 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver; + +import jakarta.servlet.http.HttpServletRequest; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.SAML2; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/AppUpdateAuthService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/AppUpdateAuthService.java index 5687a3b92..19e300585 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/AppUpdateAuthService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/AppUpdateAuthService.java @@ -1,10 +1,13 @@ package stirling.software.proprietary.security.service; import java.util.Optional; -import lombok.RequiredArgsConstructor; + import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + import stirling.software.common.configuration.interfaces.ShowAdminInterface; import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.security.database.repository.UserRepository; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomOAuth2UserService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomOAuth2UserService.java index b889a06e5..0b286e894 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomOAuth2UserService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomOAuth2UserService.java @@ -1,7 +1,7 @@ package stirling.software.proprietary.security.service; import java.util.Optional; -import lombok.extern.slf4j.Slf4j; + import org.springframework.security.authentication.LockedException; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; @@ -10,6 +10,9 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.security.oauth2.core.oidc.user.OidcUser; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.enumeration.UsernameAttribute; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java index 014666971..6ece48a4e 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java @@ -2,7 +2,7 @@ package stirling.software.proprietary.security.service; import java.util.Collection; import java.util.Set; -import lombok.RequiredArgsConstructor; + import org.springframework.security.authentication.LockedException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -10,6 +10,9 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + import stirling.software.proprietary.security.database.repository.UserRepository; import stirling.software.proprietary.security.model.Authority; import stirling.software.proprietary.security.model.User; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseService.java index 37de87cf4..6474ae7ea 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseService.java @@ -18,11 +18,15 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; + import javax.sql.DataSource; -import lombok.extern.slf4j.Slf4j; + import org.springframework.jdbc.datasource.init.CannotReadScriptException; import org.springframework.jdbc.datasource.init.ScriptException; import org.springframework.stereotype.Service; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.FileInfo; @@ -235,27 +239,27 @@ public class DatabaseService implements DatabaseServiceInterface { private boolean isH2Database() { boolean isTypeH2 = - datasourceProps.getType().equalsIgnoreCase(ApplicationProperties.Driver.H2.name()); + datasourceProps.getType().equalsIgnoreCase(ApplicationProperties.Driver.H2.name()); boolean isDBUrlH2 = - datasourceProps.getCustomDatabaseUrl().contains("h2") - || datasourceProps.getCustomDatabaseUrl().contains("H2"); + datasourceProps.getCustomDatabaseUrl().contains("h2") + || datasourceProps.getCustomDatabaseUrl().contains("H2"); boolean isCustomDatabase = datasourceProps.isEnableCustomDatabase(); if (isCustomDatabase) { if (isTypeH2 && !isDBUrlH2) { log.warn( - "Datasource type is H2, but the URL does not contain 'h2'. " - + "Please check your configuration."); + "Datasource type is H2, but the URL does not contain 'h2'. " + + "Please check your configuration."); throw new IllegalStateException( - "Datasource type is H2, but the URL does not contain 'h2'. Please check" - + " your configuration."); + "Datasource type is H2, but the URL does not contain 'h2'. Please check" + + " your configuration."); } else if (!isTypeH2 && isDBUrlH2) { log.warn( - "Datasource URL contains 'h2', but the type is not H2. " - + "Please check your configuration."); + "Datasource URL contains 'h2', but the type is not H2. " + + "Please check your configuration."); throw new IllegalStateException( - "Datasource URL contains 'h2', but the type is not H2. Please check your" - + " configuration."); + "Datasource URL contains 'h2', but the type is not H2. Please check your" + + " configuration."); } } boolean isH2 = isTypeH2 && isDBUrlH2; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/LoginAttemptService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/LoginAttemptService.java index 852fc8ab9..ecc04bac5 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/LoginAttemptService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/LoginAttemptService.java @@ -1,11 +1,15 @@ package stirling.software.proprietary.security.service; -import jakarta.annotation.PostConstruct; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; + +import org.springframework.stereotype.Service; + +import jakarta.annotation.PostConstruct; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; + import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.security.model.AttemptCounter; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java index 7bf3e2643..0823f748b 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java @@ -1,6 +1,5 @@ package stirling.software.proprietary.security.service; -import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; @@ -9,8 +8,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -25,10 +23,14 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; +import stirling.software.common.model.enumeration.Role; import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.common.service.UserServiceInterface; -import stirling.software.common.model.enumeration.Role; import stirling.software.proprietary.security.database.repository.AuthorityRepository; import stirling.software.proprietary.security.database.repository.UserRepository; import stirling.software.proprietary.security.model.AuthenticationType; @@ -84,7 +86,7 @@ public class UserService implements UserServiceInterface { public Authentication getAuthentication(String apiKey) { Optional user = getUserByApiKey(apiKey); - if (!user.isPresent()) { + if (user.isEmpty()) { throw new UsernameNotFoundException("API key is not valid"); } // Convert the user into an Authentication object @@ -301,9 +303,7 @@ public class UserService implements UserServiceInterface { } public void changeUsername(User user, String newUsername) - throws IllegalArgumentException, - SQLException, - UnsupportedProviderException { + throws IllegalArgumentException, SQLException, UnsupportedProviderException { if (!isUsernameValid(newUsername)) { throw new IllegalArgumentException(getInvalidUsernameMessage()); } diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/session/CustomHttpSessionListener.java b/proprietary/src/main/java/stirling/software/proprietary/security/session/CustomHttpSessionListener.java index 7ed0f6506..b69dfaefb 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/session/CustomHttpSessionListener.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/session/CustomHttpSessionListener.java @@ -1,15 +1,17 @@ package stirling.software.proprietary.security.session; +import org.springframework.stereotype.Component; + import jakarta.servlet.http.HttpSessionEvent; import jakarta.servlet.http.HttpSessionListener; + import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; @Component @Slf4j public class CustomHttpSessionListener implements HttpSessionListener { - private SessionPersistentRegistry sessionPersistentRegistry; + private final SessionPersistentRegistry sessionPersistentRegistry; public CustomHttpSessionListener(SessionPersistentRegistry sessionPersistentRegistry) { super(); diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionPersistentRegistry.java b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionPersistentRegistry.java index 5d482e94d..8931866ad 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionPersistentRegistry.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionPersistentRegistry.java @@ -1,6 +1,5 @@ package stirling.software.proprietary.security.session; -import jakarta.transaction.Transactional; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -8,13 +7,18 @@ import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Optional; -import lombok.RequiredArgsConstructor; + import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Component; + +import jakarta.transaction.Transactional; + +import lombok.RequiredArgsConstructor; + import stirling.software.proprietary.security.database.repository.SessionRepository; import stirling.software.proprietary.security.model.SessionEntity; import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionRegistryConfig.java b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionRegistryConfig.java index 75afbea9b..eccd7332e 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionRegistryConfig.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionRegistryConfig.java @@ -3,6 +3,7 @@ package stirling.software.proprietary.security.session; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.session.SessionRegistryImpl; + import stirling.software.proprietary.security.database.repository.SessionRepository; @Configuration @@ -14,7 +15,8 @@ public class SessionRegistryConfig { } @Bean - public SessionPersistentRegistry sessionPersistentRegistry(SessionRepository sessionRepository) { + public SessionPersistentRegistry sessionPersistentRegistry( + SessionRepository sessionRepository) { return new SessionPersistentRegistry(sessionRepository); } } diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionScheduled.java b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionScheduled.java index 83403f9f7..1f491bf4d 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionScheduled.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionScheduled.java @@ -4,11 +4,13 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.List; -import lombok.RequiredArgsConstructor; + import org.springframework.scheduling.annotation.Scheduled; import org.springframework.security.core.session.SessionInformation; import org.springframework.stereotype.Component; +import lombok.RequiredArgsConstructor; + @Component @RequiredArgsConstructor public class SessionScheduled { diff --git a/scripts/download-security-jar.sh b/scripts/download-security-jar.sh index 8216179fa..bee188d97 100644 --- a/scripts/download-security-jar.sh +++ b/scripts/download-security-jar.sh @@ -1,6 +1,6 @@ echo "Running Stirling PDF with ADDITIONAL_FEATURES_OFF=${ADDITIONAL_FEATURES_OFF} and VERSION_TAG=${VERSION_TAG}" -# Check for DOCKER_ENABLE_SECURITY and download the appropriate JAR if required -if [ "$DOCKER_ENABLE_SECURITY" = "true" ] || [ "$ADDITIONAL_FEATURES_OFF" = "false" ] && [ "$VERSION_TAG" != "alpha" ]; then +# Check for $ADDITIONAL_FEATURES_OFF and download the appropriate JAR if required +if [ "$ADDITIONAL_FEATURES_OFF" = "false" ] && [ "$VERSION_TAG" != "alpha" ]; then if [ ! -f app-security.jar ]; then echo "Trying to download from: https://files.stirlingpdf.com/v$VERSION_TAG/Stirling-PDF-with-login.jar" curl -L -o app-security.jar https://files.stirlingpdf.com/v$VERSION_TAG/Stirling-PDF-with-login.jar diff --git a/testing/test.sh b/testing/test.sh index f1169ec17..0891c6bbd 100644 --- a/testing/test.sh +++ b/testing/test.sh @@ -214,7 +214,6 @@ main() { export DOCKER_CLI_EXPERIMENTAL=enabled export COMPOSE_DOCKER_CLI_BUILD=0 - export DOCKER_ENABLE_SECURITY=false export ADDITIONAL_FEATURES_OFF=true # Run the gradlew build command and check if it fails if ! ./gradlew clean build; then @@ -243,7 +242,6 @@ main() { # run_tests "Stirling-PDF" "./exampleYmlFiles/docker-compose-latest.yml" # docker-compose -f "./exampleYmlFiles/docker-compose-latest.yml" down - export DOCKER_ENABLE_SECURITY=true export ADDITIONAL_FEATURES_OFF=false # Run the gradlew build command and check if it fails if ! ./gradlew clean build; then