Compare commits

..

10 Commits

Author SHA1 Message Date
Eleftheria Stein
76924bc923 Release 2.6.0 2021-11-16 14:21:51 +01:00
Eleftheria Stein
134f89dd41 Upgrade test dependencies 2021-11-16 13:57:45 +01:00
Eleftheria Stein
33812f7197 Upgrade MongoDB to 4.4.0
Closes gh-1967
2021-11-16 13:56:44 +01:00
Eleftheria Stein
bcf17ba3b7 Upgrade samples to Spring Boot 2.5.6
Closes gh-1966
2021-11-16 13:37:41 +01:00
Eleftheria Stein
98f656ad46 Upgrade Jackson to 2.13.0
Closes gh-1965
2021-11-16 13:11:51 +01:00
Eleftheria Stein
7832942752 Upgrade Spring Security to 5.6.0
Closes gh-1964
2021-11-16 13:07:43 +01:00
Eleftheria Stein
722069a5f8 Upgrade Spring Data to 2021.1.0
Closes gh-1963
2021-11-16 13:06:41 +01:00
Eleftheria Stein
addbdbc1a2 Upgrade Spring Framework to 5.3.13
Closes gh-1962
2021-11-16 13:05:51 +01:00
Eleftheria Stein
004466ed07 Upgrade Reactor to 2020.0.13
Closes gh-1961
2021-11-16 13:04:32 +01:00
Eleftheria Stein
aeb5bc545c Update to Gradle 7.3
Closes gh-1959
2021-11-15 09:59:22 +01:00
379 changed files with 8220 additions and 4586 deletions

9
.gitattributes vendored
View File

@@ -1,9 +0,0 @@
* text eol=lf
*.bat text eol=crlf
*.jar binary
*.png binary
*.mmdb binary

View File

@@ -14,12 +14,6 @@ jobs:
steps:
- name: Checkout Source
uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt'
cache: gradle
- name: Generate antora.yml
run: ./gradlew :spring-session-docs:generateAntora
- name: Extract Branch Name

View File

@@ -2,6 +2,8 @@ name: CI
on:
push:
branches:
- main
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
@@ -20,7 +22,7 @@ jobs:
if: github.repository == 'spring-projects/spring-session'
strategy:
matrix:
jdk: [17]
jdk: [8, 11]
fail-fast: false
steps:
- uses: actions/checkout@v2
@@ -31,7 +33,7 @@ jobs:
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
echo 'systemProp.user.name=spring-builds' >> ~/.gradle/gradle.properties
- name: Cache Gradle packages
uses: actions/cache@v2
with:
@@ -53,11 +55,11 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: '17'
java-version: '8'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
echo 'systemProp.user.name=spring-builds' >> ~/.gradle/gradle.properties
- name: Deploy artifacts
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
@@ -81,11 +83,11 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: '17'
java-version: '8'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
echo 'systemProp.user.name=spring-builds' >> ~/.gradle/gradle.properties
- name: Deploy Docs
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"

View File

@@ -13,10 +13,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '17'
java-version: '11'
distribution: 'adopt'
cache: gradle
- name: Validate Gradle wrapper

View File

@@ -9,7 +9,7 @@ jobs:
if: github.repository == 'spring-projects/spring-session'
strategy:
matrix:
jdk: [17]
jdk: [8, 11]
fail-fast: false
steps:
- uses: actions/checkout@v2

2
.gitignore vendored
View File

@@ -14,5 +14,3 @@ out
!etc/eclipse/.checkstyle
!**/src/**/build
.DS_Store
spring-session-docs/package-lock.json
spring-session-docs/node_modules/

View File

@@ -1,6 +0,0 @@
# Use sdkman to run "sdk env" to initialize with correct JDK version
# Enable auto-env through the sdkman_auto_env config
# See https://sdkman.io/usage#config
# A summary is to add the following to ~/.sdkman/etc/config
# sdkman_auto_env=true
java=17.0.2-tem

View File

@@ -19,9 +19,9 @@ This Spring Session repository consists of the following modules:
* Spring Session Data Redis - provides `SessionRepository` and `ReactiveSessionRepository` implementation backed by Redis and configuration support
* Spring Session JDBC - provides `SessionRepository` implementation backed by a relational database and configuration support
* Spring Session Hazelcast - provides `SessionRepository` implementation backed by Hazelcast and configuration support
* Spring Session MongoDB - provides `SessionRepository` implementation backed by MongoDB and configuration support
Additional Spring Session modules can be found in the https://github.com/spring-projects/spring-session-data-geode[spring-session-data-geode] repository.
Additional Spring Session modules can be found in the https://github.com/spring-projects/spring-session-data-mongodb[spring-session-data-mongodb] repository
and https://github.com/spring-projects/spring-session-data-geode[spring-session-data-geode] repository.
== Getting Started

View File

@@ -1,110 +0,0 @@
== 1. Update Dependencies
Dependencies are declared in `gradle/dependency-management.gradle`.
Update Spring Framework, Spring Security and Spring Data at a minimum.
Run all the checks:
[source,bash]
----
$ ./gradlew check
----
Create separate issues for each dependency update, aside from test dependencies which can be combined into a single commit.
== 2. Check All Issues are Closed
You can manually check at https://github.com/spring-projects/spring-session/milestones
== 3. Update Release Version
Update the version number in `gradle.properties` for the release, for example `3.0.0-M1`, `3.0.0-RC1`, `3.0.4`
== 4. Update Antora Version
You will need to update the antora.yml version.
For milestone / release candidate releases you should follow this format:
----
version: '3.0.0-RC1'
prerelease: 'true'
display_version: '3.0.0-RC1'
----
== 5. Build Locally
Run the build using
[source,bash]
----
$ ./gradlew check
----
== 6. Push the Release Commit
Push the commit and GitHub actions will build and deploy the artifacts.
Wait for the artifact to appear in https://repo1.maven.org/maven2/org/springframework/session/spring-session-core/
== 7. Tag the release
Tag the release and then push the tag
....
git tag 3.0.0-RC1
git push origin 3.0.0-RC1
....
== 8. Update to Next Development Version
Update `gradle.properties` version to next `+SNAPSHOT+` version, update antora.yml and then push
== 9. Update version on project pages
Update the versions on https://spring.io/projects for Spring Session Core, Spring Session Data Redis, Spring Session JDBC, Spring Session Hazelcast, and Spring Session MongoDB.
== 10. Update Release Notes on GitHub
Download
https://github.com/spring-io/github-changelog-generator/releases/latest[the
GitHub release notes generator]
* Generate the release notes
....
java -jar github-changelog-generator.jar \
--changelog.repository=spring-projects/spring-session \
$MILESTONE release-notes
....
Note 1: `+$MILESTONE+` is something like `+3.0.4+` or `+3.0.0-M1+`. +
Note 2: This will create a file on your filesystem
called `+release-notes+`.
* Copy the release notes to your clipboard (your mileage may vary with
the following command)
....
cat release-notes | xclip -selection clipboard
....
* Create the
https://github.com/spring-projects/spring-session/releases[release on
GitHub], associate it with the tag, and paste the generated notes.
== 11. Close / Create Milestone
* In
https://github.com/spring-projects/spring-session/milestones[GitHub
Milestones], create a new milestone for the next release version.
* Move any open issues from the existing milestone you just released to
the new milestone.
* Close the milestone for the release.
Note: Spring Session typically releases only one milestone (M1) and one release candidate (RC1).
== 12. Announce the release
* Announce via Slack on https://pivotal.slack.com/messages/spring-session[#spring-session], and tag any downstream Spring Session projects (e.g Spring Session for Apache Geode).
Note: Do not post on #spring-release or create a blog post. Those steps happen after the Spring Session BOM is released.

View File

@@ -4,7 +4,7 @@ buildscript {
snapshotBuild = version.endsWith('SNAPSHOT')
milestoneBuild = !(releaseBuild || snapshotBuild)
springBootVersion = '3.0.0-SNAPSHOT'
springBootVersion = '2.5.6'
}
repositories {
@@ -35,7 +35,7 @@ subprojects {
apply plugin: 'io.spring.javaformat'
plugins.withType(JavaPlugin) {
sourceCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_1_8
}
tasks.withType(Test) {
@@ -45,6 +45,4 @@ subprojects {
nohttp {
source.exclude "buildSrc/build/**"
source.exclude "spring-session-docs/.gradle/nodejs/**"
source.exclude "spring-session-docs/modules/ROOT/examples/**/build/**"
}

View File

@@ -4,7 +4,7 @@ plugins {
id "groovy"
}
sourceCompatibility = JavaVersion.VERSION_11
sourceCompatibility = 1.8
repositories {
jcenter()
@@ -62,9 +62,9 @@ dependencies {
implementation 'com.apollographql.apollo:apollo-runtime:2.4.5'
implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
implementation 'com.github.spullara.mustache.java:compiler:0.9.10'
implementation 'io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.34'
implementation 'io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.15'
implementation 'io.spring.nohttp:nohttp-gradle:0.0.9'
implementation 'net.sourceforge.htmlunit:htmlunit:2.37.0'
implementation 'net.sourceforge.htmlunit:htmlunit:2.55.0'
implementation 'org.hidetake:gradle-ssh-plugin:2.10.1'
implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.24.20'
implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -35,7 +35,6 @@ public abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
@Override
public final void apply(Project project) {
initialPlugins(project);
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply(JavaPlugin.class);
pluginManager.apply(ManagementConfigurationPlugin.class)
@@ -70,7 +69,5 @@ public abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
additionalPlugins(project);
}
protected void initialPlugins(Project project) {}
protected abstract void additionalPlugins(Project project);
}

View File

@@ -34,7 +34,7 @@ class JacocoPlugin implements Plugin<Project> {
project.tasks.check.dependsOn project.tasks.jacocoTestReport
project.jacoco {
toolVersion = '0.8.7'
toolVersion = '0.8.2'
}
}
}

View File

@@ -30,19 +30,4 @@ public class SpringSamplePlugin extends AbstractSpringJavaPlugin {
project.sonarqube.skipProject = true
}
}
@Override
protected void initialPlugins(Project project) {
if (project.hasProperty('springBootVersion')) {
String springBootVersion = project.springBootVersion
if (Utils.isSnapshot(springBootVersion)) {
project.ext.forceMavenRepositories = 'snapshot'
}
else if (Utils.isMilestone(springBootVersion)) {
project.ext.forceMavenRepositories = 'milestone'
}
}
}
}

View File

@@ -36,7 +36,7 @@ public class SpringSampleWarPlugin extends SpringSamplePlugin {
pluginManager.apply("org.gretty");
project.gretty {
servletContainer = 'tomcat10'
servletContainer = 'tomcat85'
contextPath = '/'
fileLogEnabled = false
}

View File

@@ -14,29 +14,16 @@ public class Utils {
static boolean isSnapshot(Project project) {
String projectVersion = projectVersion(project)
return isSnapshot(projectVersion)
return projectVersion.matches('^.*([.-]BUILD)?-SNAPSHOT$')
}
static boolean isMilestone(Project project) {
String projectVersion = projectVersion(project)
return isMilestone(projectVersion)
}
static boolean isRelease(Project project) {
String projectVersion = projectVersion(project)
return isRelease(projectVersion)
}
static boolean isSnapshot(String projectVersion) {
return projectVersion.matches('^.*([.-]BUILD)?-SNAPSHOT$')
}
static boolean isMilestone(String projectVersion) {
return projectVersion.matches('^.*[.-]M\\d+$') || projectVersion.matches('^.*[.-]RC\\d+$')
}
static boolean isRelease(String projectVersion) {
return !(isSnapshot(projectVersion) || isMilestone(projectVersion))
static boolean isRelease(Project project) {
return !(isSnapshot(project) || isMilestone(project))
}
private static String projectVersion(Project project) {

View File

@@ -28,7 +28,7 @@ public class JavadocApiPluginITest {
.build();
assertThat(result.task(":api").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
File allClasses = new File(testKit.getRootDir(), "build/api/allclasses-noframe.html");
File index = new File(testKit.getRootDir(), "build/api/allclasses-index.html");
File index = new File(testKit.getRootDir(), "build/api/allclasses.html");
File listing = allClasses.exists() ? allClasses : index;
String listingText = FileUtils.readFileToString(listing);
assertThat(listingText).contains("sample/Api.html");

View File

@@ -9,7 +9,7 @@ repositories {
}
dependencies {
optional 'jakarta.servlet:jakarta.servlet-api:5.0.0'
optional 'javax.servlet:javax.servlet-api:3.1.0'
testImplementation platform('org.junit:junit-bom:5.8.1')
testImplementation 'org.junit.jupiter:junit-jupiter-api'
testImplementation 'org.junit.jupiter:junit-jupiter-engine'

View File

@@ -1,7 +1,7 @@
package sample;
import org.junit.jupiter.api.Test;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
public class TheTest {
@Test

View File

@@ -1,10 +1,10 @@
plugins {
id "org.gretty" version "4.0.0"
id "org.gretty" version "3.0.7"
id "io.spring.convention.spring-sample-war"
}
dependencies {
provided 'jakarta.servlet:jakarta.servlet-api:5.0.0'
provided 'javax.servlet:javax.servlet-api'
testImplementation 'commons-io:commons-io:2.11.0'
testImplementation 'org.assertj:assertj-core:3.21.0'
testImplementation platform('org.junit:junit-bom:5.8.1')

View File

@@ -18,11 +18,11 @@ package sample;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class HelloServlet extends HttpServlet {

View File

@@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.parallel=true
version=3.0.0-RC2
version=2.6.0

View File

@@ -1,45 +1,49 @@
dependencyManagement {
imports {
mavenBom 'io.projectreactor:reactor-bom:2022.0.0'
mavenBom 'com.fasterxml.jackson:jackson-bom:2.13.4.20221013'
mavenBom 'org.junit:junit-bom:5.9.1'
mavenBom 'org.mockito:mockito-bom:4.8.1'
mavenBom 'org.springframework:spring-framework-bom:6.0.0-RC4'
mavenBom 'org.springframework.data:spring-data-bom:2022.0.0-RC2'
mavenBom 'org.springframework.security:spring-security-bom:6.0.0-RC2'
mavenBom 'org.testcontainers:testcontainers-bom:1.17.3'
mavenBom 'io.projectreactor:reactor-bom:2020.0.13'
mavenBom 'com.fasterxml.jackson:jackson-bom:2.13.0'
mavenBom 'org.junit:junit-bom:5.8.1'
mavenBom 'org.springframework:spring-framework-bom:5.3.13'
mavenBom 'org.springframework.data:spring-data-bom:2021.1.0'
mavenBom 'org.springframework.security:spring-security-bom:5.6.0'
mavenBom 'org.testcontainers:testcontainers-bom:1.16.2'
}
dependencies {
dependency 'com.hazelcast:hazelcast:5.1.4'
dependency 'org.aspectj:aspectjweaver:1.9.9.1'
dependency 'ch.qos.logback:logback-core:1.4.4'
dependency 'com.google.code.findbugs:jsr305:3.0.2'
dependency 'com.h2database:h2:2.1.214'
dependency 'com.ibm.db2:jcc:11.5.7.0'
dependency 'com.microsoft.sqlserver:mssql-jdbc:11.2.1.jre17'
dependency 'com.oracle.database.jdbc:ojdbc8:21.7.0.0'
dependency 'com.zaxxer:HikariCP:5.0.1'
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
dependency 'io.lettuce:lettuce-core:6.2.1.RELEASE'
dependency 'jakarta.servlet:jakarta.servlet-api:6.0.0'
dependency 'jakarta.websocket:jakarta.websocket-api:2.1.0'
dependency 'jakarta.websocket:jakarta.websocket-client-api:2.1.0'
dependency 'mysql:mysql-connector-java:8.0.30'
dependencySet(group: 'org.apache.derby', version: '10.16.1.1') {
entry 'derby'
entry 'derbytools'
dependencySet(group: 'com.hazelcast', version: '3.12.12') {
entry 'hazelcast'
entry 'hazelcast-client'
}
dependency 'org.assertj:assertj-core:3.23.1'
dependency 'org.hamcrest:hamcrest:2.2'
dependency 'org.hsqldb:hsqldb:2.7.0'
dependency 'org.mariadb.jdbc:mariadb-java-client:3.0.7'
dependencySet(group: 'org.mongodb', version: '4.8.0-beta0') {
dependency 'org.aspectj:aspectjweaver:1.9.7'
dependency 'ch.qos.logback:logback-core:1.2.3'
dependency 'com.google.code.findbugs:jsr305:3.0.2'
dependency 'com.h2database:h2:1.4.200'
dependency 'com.ibm.db2:jcc:11.5.6.0'
dependency 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre8'
dependency 'com.oracle.database.jdbc:ojdbc8:21.3.0.0'
dependency 'com.zaxxer:HikariCP:3.4.5'
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
dependency 'io.lettuce:lettuce-core:6.1.5.RELEASE'
dependency 'javax.annotation:javax.annotation-api:1.3.2'
dependency 'javax.servlet:javax.servlet-api:4.0.1'
dependency 'mysql:mysql-connector-java:8.0.27'
dependency 'org.apache.derby:derby:10.14.2.0'
dependency 'org.assertj:assertj-core:3.21.0'
dependency 'org.hamcrest:hamcrest:2.1'
dependency 'org.hsqldb:hsqldb:2.5.2'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.7.4'
dependencySet(group: 'org.mockito', version: '4.0.0') {
entry 'mockito-core'
entry 'mockito-junit-jupiter'
}
dependencySet(group: 'org.mongodb', version: '4.4.0') {
entry 'mongodb-driver-core'
entry 'mongodb-driver-sync'
entry 'mongodb-driver-reactivestreams'
}
dependency 'org.postgresql:postgresql:42.5.0'
dependency 'org.postgresql:postgresql:42.3.1'
}
}

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

6
gradlew vendored
View File

@@ -205,12 +205,6 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.

180
gradlew.bat vendored
View File

@@ -1,91 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="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!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -6,19 +6,20 @@ pluginManagement {
}
plugins {
id "com.gradle.enterprise" version "3.11.2"
id "com.gradle.enterprise" version "3.5.1"
id "io.spring.ge.conventions" version "0.0.7"
}
rootProject.name = 'spring-session-build'
include 'spring-session-bom'
include 'spring-session-core'
include 'spring-session-data-mongodb'
include 'spring-session-data-redis'
include 'spring-session-docs'
include 'spring-session-hazelcast'
include 'spring-session-jdbc'
include 'hazelcast4'
project(':hazelcast4').projectDir = file('spring-session-hazelcast/hazelcast4')
file('spring-session-samples').eachDirMatch(~/spring-session-sample-.*/) { dir ->
include dir.name

View File

@@ -1,15 +0,0 @@
import io.spring.gradle.convention.SpringModulePlugin
plugins {
id("io.spring.convention.bom")
}
dependencies {
constraints {
project.rootProject.allprojects { project ->
project.plugins.withType(SpringModulePlugin) {
api(project)
}
}
}
}

View File

@@ -6,7 +6,8 @@ dependencies {
api "org.springframework:spring-jcl"
optional "io.projectreactor:reactor-core"
optional "jakarta.servlet:jakarta.servlet-api"
optional "javax.annotation:javax.annotation-api"
optional "javax.servlet:javax.servlet-api"
optional "org.springframework:spring-context"
optional "org.springframework:spring-jdbc"
optional "org.springframework:spring-messaging"
@@ -18,8 +19,6 @@ dependencies {
testImplementation "io.projectreactor:reactor-test"
testImplementation "org.mockito:mockito-core"
testImplementation "org.mockito:mockito-junit-jupiter"
testImplementation "org.mockito:mockito-inline"
testImplementation "edu.umd.cs.mtc:multithreadedtc"
testImplementation "org.springframework:spring-test"
testImplementation "org.assertj:assertj-core"

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,16 +48,10 @@ import java.util.UUID;
*/
public final class MapSession implements Session, Serializable {
/**
* Default {@link #setMaxInactiveInterval(Duration)} (30 minutes) in seconds.
*/
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
/**
* Default {@link #setMaxInactiveInterval(Duration)} (30 minutes).
*/
public static final Duration DEFAULT_MAX_INACTIVE_INTERVAL = Duration
.ofSeconds(DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
private String id;
@@ -72,7 +66,7 @@ public final class MapSession implements Session, Serializable {
/**
* Defaults to 30 minutes.
*/
private Duration maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL;
private Duration maxInactiveInterval = Duration.ofSeconds(DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
/**
* Creates a new instance with a secure randomly generated identifier.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ import java.util.Map;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.util.Assert;
/**
* A {@link SessionRepository} backed by a {@link java.util.Map} and that uses a
@@ -39,7 +38,11 @@ import org.springframework.util.Assert;
*/
public class MapSessionRepository implements SessionRepository<MapSession> {
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
/**
* If non-null, this value is used to override
* {@link Session#setMaxInactiveInterval(Duration)}.
*/
private Integer defaultMaxInactiveInterval;
private final Map<String, Session> sessions;
@@ -56,13 +59,12 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
}
/**
* Set the maximum inactive interval in seconds between requests before newly created
* sessions will be invalidated. A negative time indicates that the session will never
* time out. The default is 30 minutes.
* @param defaultMaxInactiveInterval the default maxInactiveInterval
* If non-null, this value is used to override
* {@link Session#setMaxInactiveInterval(Duration)}.
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session}
* should be kept alive between client requests.
*/
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
}
@@ -95,7 +97,9 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
@Override
public MapSession createSession() {
MapSession result = new MapSession();
result.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
if (this.defaultMaxInactiveInterval != null) {
result.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
}
return result;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@ import reactor.core.publisher.Mono;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.util.Assert;
/**
* A {@link ReactiveSessionRepository} backed by a {@link Map} and that uses a
@@ -41,7 +40,11 @@ import org.springframework.util.Assert;
*/
public class ReactiveMapSessionRepository implements ReactiveSessionRepository<MapSession> {
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
/**
* If non-null, this value is used to override
* {@link Session#setMaxInactiveInterval(Duration)}.
*/
private Integer defaultMaxInactiveInterval;
private final Map<String, Session> sessions;
@@ -58,13 +61,12 @@ public class ReactiveMapSessionRepository implements ReactiveSessionRepository<M
}
/**
* Set the maximum inactive interval in seconds between requests before newly created
* sessions will be invalidated. A negative time indicates that the session will never
* time out. The default is 30 minutes.
* @param defaultMaxInactiveInterval the default maxInactiveInterval
* If non-null, this value is used to override
* {@link Session#setMaxInactiveInterval(Duration)}.
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session}
* should be kept alive between client requests.
*/
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
}
@@ -97,7 +99,9 @@ public class ReactiveMapSessionRepository implements ReactiveSessionRepository<M
public Mono<MapSession> createSession() {
return Mono.defer(() -> {
MapSession result = new MapSession();
result.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
if (this.defaultMaxInactiveInterval != null) {
result.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
}
return Mono.just(result);
});
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.aot.hint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
/**
* A {@link RuntimeHintsRegistrar} for common session hints.
*
* @author Marcus Da Coregio
*/
class CommonSessionRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
Arrays.asList(TypeReference.of(String.class), TypeReference.of(ArrayList.class),
TypeReference.of(TreeSet.class), TypeReference.of(Number.class), TypeReference.of(Long.class),
TypeReference.of(Integer.class), TypeReference.of(StackTraceElement.class),
TypeReference.of(Throwable.class), TypeReference.of(Exception.class),
TypeReference.of(RuntimeException.class),
TypeReference.of("java.util.Collections$UnmodifiableCollection"),
TypeReference.of("java.util.Collections$UnmodifiableList"),
TypeReference.of("java.util.Collections$EmptyList"),
TypeReference.of("java.util.Collections$UnmodifiableRandomAccessList"),
TypeReference.of("java.util.Collections$UnmodifiableSet")).forEach(hints.serialization()::registerType);
}
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.aot.hint;
import java.util.Arrays;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
/**
* A {@link RuntimeHintsRegistrar} for common session security hints.
*
* @author Marcus Da Coregio
*/
class CommonSessionSecurityRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
registerSecurityHintsIfNeeded(hints);
registerOAuth2ClientHintsIfNeeded(hints);
registerOAuth2ResourceServerHintsIfNeeded(hints);
}
private void registerSecurityHintsIfNeeded(RuntimeHints hints) {
Arrays.asList(TypeReference.of("org.springframework.security.core.context.SecurityContextImpl"),
TypeReference.of("org.springframework.security.core.authority.SimpleGrantedAuthority"),
TypeReference.of("org.springframework.security.core.userdetails.User"),
TypeReference.of("org.springframework.security.authentication.AbstractAuthenticationToken"),
TypeReference.of("org.springframework.security.authentication.UsernamePasswordAuthenticationToken"),
TypeReference.of("org.springframework.security.core.AuthenticationException"),
TypeReference.of("org.springframework.security.authentication.BadCredentialsException"),
TypeReference.of("org.springframework.security.core.userdetails.UsernameNotFoundException"),
TypeReference.of("org.springframework.security.authentication.AccountExpiredException"),
TypeReference.of("org.springframework.security.authentication.ProviderNotFoundException"),
TypeReference.of("org.springframework.security.authentication.DisabledException"),
TypeReference.of("org.springframework.security.authentication.LockedException"),
TypeReference.of("org.springframework.security.authentication.AuthenticationServiceException"),
TypeReference.of("org.springframework.security.authentication.CredentialsExpiredException"),
TypeReference.of("org.springframework.security.authentication.InsufficientAuthenticationException"),
TypeReference
.of("org.springframework.security.web.authentication.session.SessionAuthenticationException"),
TypeReference.of(
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException"),
TypeReference.of("org.springframework.security.core.userdetails.User$AuthorityComparator"))
.forEach((type) -> hints.serialization().registerType(type, (hint) -> hint.onReachableType(
TypeReference.of("org.springframework.security.core.context.SecurityContextImpl"))));
}
private void registerOAuth2ResourceServerHintsIfNeeded(RuntimeHints hints) {
Arrays.asList(
TypeReference.of("org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken"),
TypeReference.of(
"org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken"),
TypeReference.of("org.springframework.security.oauth2.core.OAuth2AuthenticationException"))
.forEach((type) -> hints.serialization().registerType(type, (hint) -> hint.onReachableType(TypeReference
.of("org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken"))));
}
private void registerOAuth2ClientHintsIfNeeded(RuntimeHints hints) {
Arrays.asList(
TypeReference.of("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken"),
TypeReference
.of("org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken"),
TypeReference.of(
"org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken"),
TypeReference.of("org.springframework.security.oauth2.core.OAuth2AuthenticationException"))
.forEach((type) -> hints.serialization().registerType(type, (hint) -> hint.onReachableType(TypeReference
.of("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken"))));
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.aot.hint.server;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.security.web.server.csrf.DefaultCsrfToken;
import org.springframework.util.ClassUtils;
/**
* {@link RuntimeHintsRegistrar} for Reactive Session hints.
*
* @author Marcus Da Coregio
*/
class WebSessionSecurityRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
if (!ClassUtils.isPresent("org.springframework.web.server.WebSession", classLoader) || !ClassUtils
.isPresent("org.springframework.security.web.server.csrf.DefaultCsrfToken", classLoader)) {
return;
}
hints.serialization().registerType(DefaultCsrfToken.class);
}
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.aot.hint.servlet;
import java.util.Arrays;
import java.util.Locale;
import java.util.TreeMap;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.savedrequest.DefaultSavedRequest;
import org.springframework.security.web.savedrequest.SavedCookie;
import org.springframework.util.ClassUtils;
/**
* {@link RuntimeHintsRegistrar} for Servlet Session hints.
*
* @author Marcus Da Coregio
*/
class HttpSessionSecurityRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
if (!ClassUtils.isPresent("jakarta.servlet.http.HttpSession", classLoader)
|| !ClassUtils.isPresent("org.springframework.security.web.csrf.DefaultCsrfToken", classLoader)) {
return;
}
Arrays.asList(TypeReference.of(TreeMap.class), TypeReference.of(Locale.class),
TypeReference.of(DefaultSavedRequest.class), TypeReference.of(DefaultCsrfToken.class),
TypeReference.of(WebAuthenticationDetails.class), TypeReference.of(SavedCookie.class),
TypeReference.of("java.lang.String$CaseInsensitiveComparator"))
.forEach(hints.serialization()::registerType);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.session.SessionRepository;
import org.springframework.session.events.SessionCreatedEvent;
@@ -33,7 +34,7 @@ import org.springframework.session.events.SessionDestroyedEvent;
*
* <pre>
* <code>
* {@literal @Configuration(proxyBeanMethods = false)}
* {@literal @Configuration}
* {@literal @EnableSpringHttpSession}
* public class SpringHttpSessionConfig {
*
@@ -73,6 +74,7 @@ import org.springframework.session.events.SessionDestroyedEvent;
@Target({ java.lang.annotation.ElementType.TYPE })
@Documented
@Import(SpringHttpSessionConfiguration.class)
@Configuration(proxyBeanMethods = false)
public @interface EnableSpringHttpSession {
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,15 +19,15 @@ package org.springframework.session.config.annotation.web.http;
import java.util.ArrayList;
import java.util.List;
import jakarta.servlet.ServletContext;
import jakarta.servlet.SessionCookieConfig;
import jakarta.servlet.http.HttpSessionListener;
import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import javax.servlet.SessionCookieConfig;
import javax.servlet.http.HttpSessionListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -91,7 +91,7 @@ import org.springframework.util.ObjectUtils;
* @see EnableSpringHttpSession
*/
@Configuration(proxyBeanMethods = false)
public class SpringHttpSessionConfiguration implements InitializingBean, ApplicationContextAware {
public class SpringHttpSessionConfiguration implements ApplicationContextAware {
private final Log logger = LogFactory.getLog(getClass());
@@ -107,8 +107,8 @@ public class SpringHttpSessionConfiguration implements InitializingBean, Applica
private List<HttpSessionListener> httpSessionListeners = new ArrayList<>();
@Override
public void afterPropertiesSet() {
@PostConstruct
public void init() {
CookieSerializer cookieSerializer = (this.cookieSerializer != null) ? this.cookieSerializer
: createDefaultCookieSerializer();
this.defaultHttpSessionIdResolver.setCookieSerializer(cookieSerializer);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
@@ -30,7 +31,7 @@ import org.springframework.context.annotation.Import;
*
* <pre>
* <code>
* {@literal @Configuration(proxyBeanMethods = false)}
* {@literal @Configuration}
* {@literal @EnableSpringWebSession}
* public class SpringWebFluxConfig {
*
@@ -49,6 +50,7 @@ import org.springframework.context.annotation.Import;
@Target({ java.lang.annotation.ElementType.TYPE })
@Documented
@Import(SpringWebSessionConfiguration.class)
@Configuration(proxyBeanMethods = false)
public @interface EnableSpringWebSession {
}

View File

@@ -16,9 +16,9 @@
package org.springframework.session.security.web.authentication;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,10 +19,10 @@ package org.springframework.session.web.context;
import java.util.Arrays;
import java.util.EnumSet;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterRegistration.Dynamic;
import jakarta.servlet.ServletContext;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration.Dynamic;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;
import org.springframework.core.Conventions;

View File

@@ -18,8 +18,8 @@ package org.springframework.session.web.http;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.session.web.http.CookieSerializer.CookieValue;
@@ -32,8 +32,8 @@ import org.springframework.session.web.http.CookieSerializer.CookieValue;
* When a session is created, the HTTP response will have a cookie with the specified
* cookie name and the value of the session id. The cookie will be marked as a session
* cookie, use the context path for the path of the cookie, marked as HTTPOnly, and if
* {@link jakarta.servlet.http.HttpServletRequest#isSecure()} returns true, the cookie
* will be marked as secure. For example:
* {@link javax.servlet.http.HttpServletRequest#isSecure()} returns true, the cookie will
* be marked as secure. For example:
*
* <pre>
* HTTP/1.1 200 OK

View File

@@ -18,9 +18,9 @@ package org.springframework.session.web.http;
import java.util.List;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Strategy for reading and writing a cookie value to the {@link HttpServletResponse}.

View File

@@ -28,9 +28,9 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -88,8 +88,7 @@ public class DefaultCookieSerializer implements CookieSerializer {
private String sameSite = "Lax";
/*
* @see
* org.springframework.session.web.http.CookieSerializer#readCookieValues(jakarta.
* @see org.springframework.session.web.http.CookieSerializer#readCookieValues(javax.
* servlet.http.HttpServletRequest)
*/
@Override

View File

@@ -19,8 +19,8 @@ package org.springframework.session.web.http;
import java.util.Collections;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A {@link HttpSessionIdResolver} that uses a header to resolve the session id.
@@ -98,7 +98,6 @@ public class HeaderHttpSessionIdResolver implements HttpSessionIdResolver {
@Override
public List<String> resolveSessionIds(HttpServletRequest request) {
String headerValue = request.getHeader(this.headerName);
System.out.println(headerValue);
return (headerValue != null) ? Collections.singletonList(headerValue) : Collections.emptyList();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,11 +19,14 @@ package org.springframework.session.web.http;
import java.time.Duration;
import java.util.Collections;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Set;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -38,6 +41,7 @@ import org.springframework.session.Session;
* @author Vedran Pavic
* @since 1.1
*/
@SuppressWarnings("deprecation")
class HttpSessionAdapter<S extends Session> implements HttpSession {
private static final Log logger = LogFactory.getLog(HttpSessionAdapter.class);
@@ -97,18 +101,35 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
return (int) this.session.getMaxInactiveInterval().getSeconds();
}
@Override
public HttpSessionContext getSessionContext() {
return NOOP_SESSION_CONTEXT;
}
@Override
public Object getAttribute(String name) {
checkState();
return this.session.getAttribute(name);
}
@Override
public Object getValue(String name) {
return getAttribute(name);
}
@Override
public Enumeration<String> getAttributeNames() {
checkState();
return Collections.enumeration(this.session.getAttributeNames());
}
@Override
public String[] getValueNames() {
checkState();
Set<String> attrs = this.session.getAttributeNames();
return attrs.toArray(new String[0]);
}
@Override
public void setAttribute(String name, Object value) {
checkState();
@@ -135,6 +156,11 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
}
}
@Override
public void putValue(String name, Object value) {
setAttribute(name, value);
}
@Override
public void removeAttribute(String name) {
checkState();
@@ -150,6 +176,11 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
}
}
@Override
public void removeValue(String name) {
removeAttribute(name);
}
@Override
public void invalidate() {
checkState();
@@ -172,4 +203,32 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
}
}
private static final HttpSessionContext NOOP_SESSION_CONTEXT = new HttpSessionContext() {
@Override
public HttpSession getSession(String sessionId) {
return null;
}
@Override
public Enumeration<String> getIds() {
return EMPTY_ENUMERATION;
}
};
private static final Enumeration<String> EMPTY_ENUMERATION = new Enumeration<String>() {
@Override
public boolean hasMoreElements() {
return false;
}
@Override
public String nextElement() {
throw new NoSuchElementException("a");
}
};
}

View File

@@ -18,8 +18,8 @@ package org.springframework.session.web.http;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Contract for session id resolution strategies. Allows for session id resolution through

View File

@@ -20,14 +20,14 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
* Base class for response wrappers which encapsulate the logic for handling an event when
* the {@link jakarta.servlet.http.HttpServletResponse} is committed.
* the {@link javax.servlet.http.HttpServletResponse} is committed.
*
* @author Rob Winch
* @since 1.0
@@ -84,16 +84,16 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
/**
* Invoke this method to disable invoking
* {@link OnCommittedResponseWrapper#onResponseCommitted()} when the
* {@link jakarta.servlet.http.HttpServletResponse} is committed. This can be useful
* in the event that Async Web Requests are made.
* {@link javax.servlet.http.HttpServletResponse} is committed. This can be useful in
* the event that Async Web Requests are made.
*/
private void disableOnResponseCommitted() {
this.disableOnCommitted = true;
}
/**
* Implement the logic for handling the
* {@link jakarta.servlet.http.HttpServletResponse} being committed.
* Implement the logic for handling the {@link javax.servlet.http.HttpServletResponse}
* being committed.
*/
protected abstract void onResponseCommitted();
@@ -474,9 +474,8 @@ abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {
/**
* Ensures{@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before
* calling methods that commit the response. We delegate all methods to the original
* {@link jakarta.servlet.ServletOutputStream} to ensure that the behavior is as close
* to the original {@link jakarta.servlet.ServletOutputStream} as possible. See
* SEC-2039
* {@link javax.servlet.ServletOutputStream} to ensure that the behavior is as close
* to the original {@link javax.servlet.ServletOutputStream} as possible. See SEC-2039
*
* @author Rob Winch
*/

View File

@@ -18,15 +18,15 @@ package org.springframework.session.web.http;
import java.io.IOException;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Allows for easily ensuring that a request is only invoked once per request. This is a

View File

@@ -18,10 +18,10 @@ package org.springframework.session.web.http;
import java.util.List;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.springframework.context.ApplicationListener;
import org.springframework.session.Session;
@@ -79,8 +79,9 @@ public class SessionEventHttpSessionListenerAdapter
}
/*
* @see org.springframework.web.context.ServletContextAware#setServletContext(jakarta.
* servlet.ServletContext)
* @see
* org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet
* .ServletContext)
*/
@Override
public void setServletContext(ServletContext servletContext) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,16 +20,16 @@ import java.io.IOException;
import java.time.Instant;
import java.util.List;
import jakarta.servlet.FilterChain;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -39,29 +39,29 @@ import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
/**
* Switches the {@link jakarta.servlet.http.HttpSession} implementation to be backed by a
* Switches the {@link javax.servlet.http.HttpSession} implementation to be backed by a
* {@link org.springframework.session.Session}.
*
* The {@link SessionRepositoryFilter} wraps the
* {@link jakarta.servlet.http.HttpServletRequest} and overrides the methods to get an
* {@link jakarta.servlet.http.HttpSession} to be backed by a
* {@link javax.servlet.http.HttpServletRequest} and overrides the methods to get an
* {@link javax.servlet.http.HttpSession} to be backed by a
* {@link org.springframework.session.Session} returned by the
* {@link org.springframework.session.SessionRepository}.
*
* The {@link SessionRepositoryFilter} uses a {@link HttpSessionIdResolver} (default
* {@link CookieHttpSessionIdResolver}) to bridge logic between an
* {@link jakarta.servlet.http.HttpSession} and the
* {@link javax.servlet.http.HttpSession} and the
* {@link org.springframework.session.Session} abstraction. Specifically:
*
* <ul>
* <li>The session id is looked up using
* {@link HttpSessionIdResolver#resolveSessionIds(jakarta.servlet.http.HttpServletRequest)}
* {@link HttpSessionIdResolver#resolveSessionIds(javax.servlet.http.HttpServletRequest)}
* . The default is to look in a cookie named SESSION.</li>
* <li>The session id of newly created {@link org.springframework.session.Session} is sent
* to the client using
* {@link HttpSessionIdResolver#setSessionId(jakarta.servlet.http.HttpServletRequest, jakarta.servlet.http.HttpServletResponse, String)}
* {@link HttpSessionIdResolver#setSessionId(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, String)}
* <li>The client is notified that the session id is no longer valid with
* {@link HttpSessionIdResolver#expireSession(jakarta.servlet.http.HttpServletRequest, jakarta.servlet.http.HttpServletResponse)}
* {@link HttpSessionIdResolver#expireSession(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
* </li>
* </ul>
*
@@ -75,7 +75,6 @@ import org.springframework.session.SessionRepository;
* @author Rob Winch
* @author Vedran Pavic
* @author Josh Cummings
* @author Yanming Zhou
* @since 1.0
*/
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
@@ -184,8 +183,8 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
}
/**
* A {@link jakarta.servlet.http.HttpServletRequest} that retrieves the
* {@link jakarta.servlet.http.HttpSession} using a
* A {@link javax.servlet.http.HttpServletRequest} that retrieves the
* {@link javax.servlet.http.HttpSession} using a
* {@link org.springframework.session.SessionRepository}.
*
* @author Rob Winch
@@ -223,11 +222,10 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
}
else {
S session = wrappedSession.getSession();
String requestedSessionId = getRequestedSessionId();
clearRequestedSessionCache();
SessionRepositoryFilter.this.sessionRepository.save(session);
String sessionId = session.getId();
if (!isRequestedSessionIdValid() || !sessionId.equals(requestedSessionId)) {
if (!isRequestedSessionIdValid() || !sessionId.equals(getRequestedSessionId())) {
SessionRepositoryFilter.this.httpSessionIdResolver.setSessionId(this, this.response, sessionId);
}
}
@@ -267,7 +265,14 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
if (requestedSession != null) {
requestedSession.setLastAccessedTime(Instant.now());
}
this.requestedSessionIdValid = (requestedSession != null);
return isRequestedSessionIdValid(requestedSession);
}
return this.requestedSessionIdValid;
}
private boolean isRequestedSessionIdValid(S session) {
if (this.requestedSessionIdValid == null) {
this.requestedSessionIdValid = session != null;
}
return this.requestedSessionIdValid;
}
@@ -351,6 +356,7 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
S session = SessionRepositoryFilter.this.sessionRepository.findById(sessionId);
if (session != null) {
this.requestedSession = session;
this.requestedSessionId = sessionId;
break;
}
}

View File

@@ -21,7 +21,7 @@ import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
import jakarta.servlet.http.HttpSession;
import javax.servlet.http.HttpSession;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;

View File

@@ -1,5 +0,0 @@
org.springframework.aot.hint.RuntimeHintsRegistrar=\
org.springframework.session.aot.hint.CommonSessionRuntimeHints,\
org.springframework.session.aot.hint.CommonSessionSecurityRuntimeHints,\
org.springframework.session.aot.hint.servlet.HttpSessionSecurityRuntimeHints,\
org.springframework.session.aot.hint.server.WebSessionSecurityRuntimeHints

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -60,8 +60,8 @@ class MapSessionRepositoryTests {
@Test
void createSessionCustomDefaultExpiration() {
Duration expectedMaxInterval = new MapSession().getMaxInactiveInterval().plusSeconds(10);
this.repository.setDefaultMaxInactiveInterval(expectedMaxInterval);
final Duration expectedMaxInterval = new MapSession().getMaxInactiveInterval().plusSeconds(10);
this.repository.setDefaultMaxInactiveInterval((int) expectedMaxInterval.getSeconds());
Session session = this.repository.createSession();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -103,8 +103,8 @@ class ReactiveMapSessionRepositoryTests {
@Test
void createSessionWhenCustomMaxInactiveIntervalThenCustomMaxInactiveInterval() {
Duration expectedMaxInterval = new MapSession().getMaxInactiveInterval().plusSeconds(10);
this.repository.setDefaultMaxInactiveInterval(expectedMaxInterval);
final Duration expectedMaxInterval = new MapSession().getMaxInactiveInterval().plusSeconds(10);
this.repository.setDefaultMaxInactiveInterval((int) expectedMaxInterval.getSeconds());
Session session = this.repository.createSession().block();

View File

@@ -1,74 +0,0 @@
/*
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.aot.hint;
import java.util.ArrayList;
import java.util.TreeSet;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.core.io.support.SpringFactoriesLoader;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link CommonSessionRuntimeHints}
*
* @author Marcus Da Coregio
*/
class CommonSessionRuntimeHintsTests {
private final RuntimeHints hints = new RuntimeHints();
private final CommonSessionRuntimeHints commonSessionRuntimeHints = new CommonSessionRuntimeHints();
@ParameterizedTest
@MethodSource("getSerializationHintTypes")
void commonSessionTypesHasHints(TypeReference typeReference) {
this.commonSessionRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.serialization().onType(typeReference)).accepts(this.hints);
}
@Test
void aotFactoriesContainsRegistrar() {
boolean match = SpringFactoriesLoader.forResourceLocation("META-INF/spring/aot.factories")
.load(RuntimeHintsRegistrar.class).stream()
.anyMatch((registrar) -> registrar instanceof CommonSessionRuntimeHints);
assertThat(match).isTrue();
}
private static Stream<TypeReference> getSerializationHintTypes() {
return Stream.of(TypeReference.of(String.class), TypeReference.of(ArrayList.class),
TypeReference.of(TreeSet.class), TypeReference.of(Number.class), TypeReference.of(Long.class),
TypeReference.of(Integer.class), TypeReference.of(StackTraceElement.class),
TypeReference.of(Throwable.class), TypeReference.of(Exception.class),
TypeReference.of(RuntimeException.class),
TypeReference.of("java.util.Collections$UnmodifiableCollection"),
TypeReference.of("java.util.Collections$UnmodifiableList"),
TypeReference.of("java.util.Collections$EmptyList"),
TypeReference.of("java.util.Collections$UnmodifiableRandomAccessList"),
TypeReference.of("java.util.Collections$UnmodifiableSet"));
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.aot.hint;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.core.io.support.SpringFactoriesLoader;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link CommonSessionSecurityRuntimeHints}
*
* @author Marcus Da Coregio
*/
class CommonSessionSecurityRuntimeHintsTests {
private final RuntimeHints hints = new RuntimeHints();
private final CommonSessionSecurityRuntimeHints commonSessionSecurityRuntimeHints = new CommonSessionSecurityRuntimeHints();
@ParameterizedTest
@MethodSource("getSerializationHintTypes")
void commonSecurityTypesHasHints(TypeReference typeReference) {
this.commonSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.serialization().onType(typeReference)).accepts(this.hints);
}
@Test
void aotFactoriesContainsRegistrar() {
boolean match = SpringFactoriesLoader.forResourceLocation("META-INF/spring/aot.factories")
.load(RuntimeHintsRegistrar.class).stream()
.anyMatch((registrar) -> registrar instanceof CommonSessionSecurityRuntimeHints);
assertThat(match).isTrue();
}
private static Stream<TypeReference> getSerializationHintTypes() {
return Stream.of(TypeReference.of("org.springframework.security.core.context.SecurityContextImpl"),
TypeReference.of("org.springframework.security.core.authority.SimpleGrantedAuthority"),
TypeReference.of("org.springframework.security.core.userdetails.User"),
TypeReference.of("org.springframework.security.authentication.AbstractAuthenticationToken"),
TypeReference.of("org.springframework.security.authentication.UsernamePasswordAuthenticationToken"),
TypeReference.of("org.springframework.security.core.AuthenticationException"),
TypeReference.of("org.springframework.security.authentication.BadCredentialsException"),
TypeReference.of("org.springframework.security.core.userdetails.UsernameNotFoundException"),
TypeReference.of("org.springframework.security.authentication.AccountExpiredException"),
TypeReference.of("org.springframework.security.authentication.ProviderNotFoundException"),
TypeReference.of("org.springframework.security.authentication.DisabledException"),
TypeReference.of("org.springframework.security.authentication.LockedException"),
TypeReference.of("org.springframework.security.authentication.AuthenticationServiceException"),
TypeReference.of("org.springframework.security.authentication.CredentialsExpiredException"),
TypeReference.of("org.springframework.security.authentication.InsufficientAuthenticationException"),
TypeReference
.of("org.springframework.security.web.authentication.session.SessionAuthenticationException"),
TypeReference.of(
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException"),
TypeReference.of("org.springframework.security.core.userdetails.User$AuthorityComparator"),
TypeReference.of("org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken"),
TypeReference.of(
"org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken"),
TypeReference.of("org.springframework.security.oauth2.core.OAuth2AuthenticationException"),
TypeReference.of("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken"),
TypeReference
.of("org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken"),
TypeReference.of(
"org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken"),
TypeReference.of("org.springframework.security.oauth2.core.OAuth2AuthenticationException"));
}
}

View File

@@ -1,81 +0,0 @@
/*
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.aot.hint.server;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.security.web.server.csrf.DefaultCsrfToken;
import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mockStatic;
/**
* Tests for {@link WebSessionSecurityRuntimeHints}
*
* @author Marcus Da Coregio
*/
class WebSessionSecurityRuntimeHintsTests {
private final RuntimeHints hints = new RuntimeHints();
private final WebSessionSecurityRuntimeHints webSessionSecurityRuntimeHints = new WebSessionSecurityRuntimeHints();
@Test
void defaultCsrfTokenHasHints() {
this.webSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.serialization().onType(DefaultCsrfToken.class)).accepts(this.hints);
}
@Test
void registerHintsWhenWebSessionMissingThenDoNotRegisterHints() {
try (MockedStatic<ClassUtils> classUtilsMock = mockStatic(ClassUtils.class)) {
classUtilsMock.when(() -> ClassUtils.isPresent(eq("org.springframework.web.server.WebSession"), any()))
.thenReturn(false);
this.webSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
assertThat(this.hints.serialization().javaSerializationHints()).isEmpty();
}
}
@Test
void registerHintsWhenDefaultCsrfTokenMissingThenDoNotRegisterHints() {
try (MockedStatic<ClassUtils> classUtilsMock = mockStatic(ClassUtils.class)) {
classUtilsMock
.when(() -> ClassUtils
.isPresent(eq("org.springframework.security.web.server.csrf.DefaultCsrfToken"), any()))
.thenReturn(false);
this.webSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
assertThat(this.hints.serialization().javaSerializationHints()).isEmpty();
}
}
@Test
void aotFactoriesContainsRegistrar() {
boolean match = SpringFactoriesLoader.forResourceLocation("META-INF/spring/aot.factories")
.load(RuntimeHintsRegistrar.class).stream()
.anyMatch((registrar) -> registrar instanceof WebSessionSecurityRuntimeHints);
assertThat(match).isTrue();
}
}

View File

@@ -1,98 +0,0 @@
/*
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.aot.hint.servlet;
import java.util.Locale;
import java.util.TreeMap;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.MockedStatic;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.savedrequest.DefaultSavedRequest;
import org.springframework.security.web.savedrequest.SavedCookie;
import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mockStatic;
/**
* Tests for {@link HttpSessionSecurityRuntimeHints}
*
* @author Marcus Da Coregio
*/
class HttpSessionSecurityRuntimeHintsTests {
private final RuntimeHints hints = new RuntimeHints();
private final HttpSessionSecurityRuntimeHints httpSessionSecurityRuntimeHints = new HttpSessionSecurityRuntimeHints();
@ParameterizedTest
@MethodSource("getSerializationHintTypes")
void httpSessionHasHints(TypeReference typeReference) {
this.httpSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.serialization().onType(typeReference)).accepts(this.hints);
}
@Test
void registerHintsWhenHttpSessionMissingThenDoNotRegisterHints() {
try (MockedStatic<ClassUtils> classUtilsMock = mockStatic(ClassUtils.class)) {
classUtilsMock.when(() -> ClassUtils.isPresent(eq("jakarta.servlet.http.HttpSession"), any()))
.thenReturn(false);
this.httpSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
assertThat(this.hints.serialization().javaSerializationHints()).isEmpty();
}
}
@Test
void registerHintsWhenDefaultCsrfTokenMissingThenDoNotRegisterHints() {
try (MockedStatic<ClassUtils> classUtilsMock = mockStatic(ClassUtils.class)) {
classUtilsMock.when(
() -> ClassUtils.isPresent(eq("org.springframework.security.web.csrf.DefaultCsrfToken"), any()))
.thenReturn(false);
this.httpSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
assertThat(this.hints.serialization().javaSerializationHints()).isEmpty();
}
}
@Test
void aotFactoriesContainsRegistrar() {
boolean match = SpringFactoriesLoader.forResourceLocation("META-INF/spring/aot.factories")
.load(RuntimeHintsRegistrar.class).stream()
.anyMatch((registrar) -> registrar instanceof HttpSessionSecurityRuntimeHints);
assertThat(match).isTrue();
}
private static Stream<TypeReference> getSerializationHintTypes() {
return Stream.of(TypeReference.of(TreeMap.class), TypeReference.of(Locale.class),
TypeReference.of(DefaultSavedRequest.class), TypeReference.of(DefaultCsrfToken.class),
TypeReference.of(WebAuthenticationDetails.class), TypeReference.of(SavedCookie.class),
TypeReference.of("java.lang.String$CaseInsensitiveComparator"));
}
}

View File

@@ -19,10 +19,10 @@ package org.springframework.session.config.annotation.web.http;
import java.io.IOException;
import java.util.Collections;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

View File

@@ -18,7 +18,7 @@ package org.springframework.session.config.annotation.web.http;
import java.util.concurrent.ConcurrentHashMap;
import jakarta.servlet.ServletContext;
import javax.servlet.ServletContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.ReactiveMapSessionRepository;
import org.springframework.session.ReactiveSessionRepository;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
@@ -106,7 +105,6 @@ class SpringWebSessionConfigurationTests {
/**
* A configuration with all the right parts.
*/
@Configuration(proxyBeanMethods = false)
@EnableSpringWebSession
static class GoodConfig {
@@ -124,13 +122,11 @@ class SpringWebSessionConfigurationTests {
/**
* A configuration where no {@link ReactiveSessionRepository} is defined. It's BAD!
*/
@Configuration(proxyBeanMethods = false)
@EnableSpringWebSession
static class BadConfig {
}
@Configuration(proxyBeanMethods = false)
@EnableSpringWebSession
static class OverrideSessionIdResolver {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,12 +24,12 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockitoAnnotations;
import org.springframework.security.core.AuthenticatedPrincipal;
import org.springframework.security.core.Authentication;
@@ -44,12 +44,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.mock;
import static org.mockito.BDDMockito.verify;
import static org.mockito.Mockito.withSettings;
/**
* Tests for {@link SpringSessionBackedSessionRegistry}.
*/
@ExtendWith(MockitoExtension.class)
class SpringSessionBackedSessionRegistryTest {
private static final String SESSION_ID = "sessionId";
@@ -68,6 +66,11 @@ class SpringSessionBackedSessionRegistryTest {
@InjectMocks
private SpringSessionBackedSessionRegistry<Session> sessionRegistry;
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
void sessionInformationForExistingSession() {
Session session = createSession(SESSION_ID, USER_NAME, NOW);
@@ -154,7 +157,7 @@ class SpringSessionBackedSessionRegistryTest {
private Session createSession(String sessionId, String userName, Instant lastAccessed) {
MapSession session = new MapSession(sessionId);
session.setLastAccessedTime(lastAccessed);
Authentication authentication = mock(Authentication.class, withSettings().lenient());
Authentication authentication = mock(Authentication.class);
given(authentication.getName()).willReturn(userName);
SecurityContextImpl securityContext = new SecurityContextImpl();
securityContext.setAuthentication(authentication);

View File

@@ -16,9 +16,9 @@
package org.springframework.session.security.web.authentication;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.junit.jupiter.api.Test;

View File

@@ -19,7 +19,7 @@ package org.springframework.session.web.http;
import java.util.Base64;
import java.util.Collections;
import jakarta.servlet.http.Cookie;
import javax.servlet.http.Cookie;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

View File

@@ -23,7 +23,7 @@ import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import jakarta.servlet.http.Cookie;
import javax.servlet.http.Cookie;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,25 +21,23 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockitoAnnotations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class OnCommittedResponseWrapperTests {
private static final String NL = "\r\n";
@Mock(lenient = true)
@Mock
HttpServletResponse delegate;
@Mock
@@ -54,6 +52,7 @@ class OnCommittedResponseWrapperTests {
@BeforeEach
void setup() throws Exception {
MockitoAnnotations.initMocks(this);
this.response = new OnCommittedResponseWrapper(this.delegate) {
@Override
protected void onResponseCommitted() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,12 +20,12 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.DispatcherType;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,17 +19,16 @@ package org.springframework.session.web.http;
import java.util.Arrays;
import java.util.Collections;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockitoAnnotations;
import org.springframework.mock.web.MockServletContext;
import org.springframework.session.MapSession;
@@ -48,7 +47,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
* @author Rob Winch
* @since 1.1
*/
@ExtendWith(MockitoExtension.class)
class SessionEventHttpSessionListenerAdapterTests {
@Mock
@@ -71,6 +69,7 @@ class SessionEventHttpSessionListenerAdapterTests {
@BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
this.listener = new SessionEventHttpSessionListenerAdapter(Arrays.asList(this.listener1, this.listener2));
this.listener.setServletContext(new MockServletContext());

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,28 +24,29 @@ import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionContext;
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockitoAnnotations;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
@@ -77,7 +78,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Tests for {@link SessionRepositoryFilter}.
*/
@ExtendWith(MockitoExtension.class)
@SuppressWarnings("deprecation")
class SessionRepositoryFilterTests {
@@ -98,6 +98,7 @@ class SessionRepositoryFilterTests {
@BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
this.sessions = new HashMap<>();
this.sessionRepository = new MapSessionRepository(this.sessions);
this.filter = new SessionRepositoryFilter<>(this.sessionRepository);
@@ -314,6 +315,52 @@ class SessionRepositoryFilterTests {
});
}
@Test
void doFilterValue() throws Exception {
final String ATTR = "ATTR";
final String VALUE = "VALUE";
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
wrappedRequest.getSession().putValue(ATTR, VALUE);
assertThat(wrappedRequest.getSession().getValue(ATTR)).isEqualTo(VALUE);
assertThat(Arrays.asList(wrappedRequest.getSession().getValueNames())).containsOnly(ATTR);
}
});
nextRequest();
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
assertThat(wrappedRequest.getSession().getValue(ATTR)).isEqualTo(VALUE);
assertThat(Arrays.asList(wrappedRequest.getSession().getValueNames())).containsOnly(ATTR);
}
});
nextRequest();
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
assertThat(wrappedRequest.getSession().getValue(ATTR)).isEqualTo(VALUE);
wrappedRequest.getSession().removeValue(ATTR);
assertThat(wrappedRequest.getSession().getValue(ATTR)).isNull();
}
});
nextRequest();
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
assertThat(wrappedRequest.getSession().getValue(ATTR)).isNull();
}
});
}
@Test
void doFilterIsNewTrue() throws Exception {
doFilter(new DoInFilter() {
@@ -589,6 +636,27 @@ class SessionRepositoryFilterTests {
assertThat(session.getSecure()).describedAs("Session Cookie should be marked as Secure").isTrue();
}
@Test
void doFilterSessionContext() throws Exception {
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
HttpSessionContext sessionContext = wrappedRequest.getSession().getSessionContext();
assertThat(sessionContext).isNotNull();
assertThat(sessionContext.getSession("a")).isNull();
assertThat(sessionContext.getIds()).isNotNull();
assertThat(sessionContext.getIds().hasMoreElements()).isFalse();
try {
sessionContext.getIds().nextElement();
fail("Expected Exception");
}
catch (NoSuchElementException ignored) {
}
}
});
}
// --- saving
@Test
@@ -672,6 +740,23 @@ class SessionRepositoryFilterTests {
});
}
@Test
void doFilterInvalidateValueIllegalState() throws Exception {
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
HttpSession session = wrappedRequest.getSession();
session.invalidate();
try {
session.getValue("attr");
fail("Expected Exception");
}
catch (IllegalStateException ignored) {
}
}
});
}
@Test
void doFilterInvalidateAttributeNamesIllegalState() throws Exception {
doFilter(new DoInFilter() {
@@ -689,6 +774,23 @@ class SessionRepositoryFilterTests {
});
}
@Test
void doFilterInvalidateValueNamesIllegalState() throws Exception {
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
HttpSession session = wrappedRequest.getSession();
session.invalidate();
try {
session.getValueNames();
fail("Expected Exception");
}
catch (IllegalStateException ignored) {
}
}
});
}
@Test
void doFilterInvalidateSetAttributeIllegalState() throws Exception {
doFilter(new DoInFilter() {
@@ -706,6 +808,23 @@ class SessionRepositoryFilterTests {
});
}
@Test
void doFilterInvalidatePutValueIllegalState() throws Exception {
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
HttpSession session = wrappedRequest.getSession();
session.invalidate();
try {
session.putValue("a", "b");
fail("Expected Exception");
}
catch (IllegalStateException ignored) {
}
}
});
}
@Test
void doFilterInvalidateRemoveAttributeIllegalState() throws Exception {
doFilter(new DoInFilter() {
@@ -723,6 +842,23 @@ class SessionRepositoryFilterTests {
});
}
@Test
void doFilterInvalidateRemoveValueIllegalState() throws Exception {
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
HttpSession session = wrappedRequest.getSession();
session.invalidate();
try {
session.removeValue("name");
fail("Expected Exception");
}
catch (IllegalStateException ignored) {
}
}
});
}
@Test
void doFilterInvalidateNewIllegalState() throws Exception {
doFilter(new DoInFilter() {
@@ -784,6 +920,20 @@ class SessionRepositoryFilterTests {
});
}
@Test
void doFilterInvalidateSessionContext() throws Exception {
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
HttpSession session = wrappedRequest.getSession();
session.invalidate();
// no exception
session.getSessionContext();
}
});
}
@Test
void doFilterInvalidateMaxInteractiveInterval() throws Exception {
doFilter(new DoInFilter() {
@@ -1176,8 +1326,8 @@ class SessionRepositoryFilterTests {
}
});
// 2 invocations expected: initial resolution, after invalidation
verify(sessionRepository, times(2)).findById(eq(session.getId()));
// 3 invocations expected: initial resolution, after invalidation, after commit
verify(sessionRepository, times(3)).findById(eq(session.getId()));
verify(sessionRepository).deleteById(eq(session.getId()));
verify(sessionRepository).createSession();
verify(sessionRepository).save(any());

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,9 +23,8 @@ import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockitoAnnotations;
import reactor.core.publisher.Mono;
import org.springframework.session.ReactiveSessionRepository;
@@ -44,10 +43,9 @@ import static org.mockito.Mockito.verify;
* @author Rob Winch
* @author Vedran Pavic
*/
@ExtendWith(MockitoExtension.class)
class SpringSessionWebSessionStoreTests<S extends Session> {
@Mock(lenient = true)
@Mock
private ReactiveSessionRepository<S> sessionRepository;
@Mock
@@ -60,6 +58,7 @@ class SpringSessionWebSessionStoreTests<S extends Session> {
@BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
this.webSessionStore = new SpringSessionWebSessionStore<>(this.sessionRepository);
given(this.sessionRepository.findById(any())).willReturn(Mono.just(this.findByIdSession));
given(this.sessionRepository.createSession()).willReturn(Mono.just(this.createSession));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,11 +18,10 @@ package org.springframework.session.web.socket.handler;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockitoAnnotations;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
@@ -36,7 +35,6 @@ import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class WebSocketConnectHandlerDecoratorFactoryTests {
@Mock
@@ -55,6 +53,7 @@ class WebSocketConnectHandlerDecoratorFactoryTests {
@BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
this.factory = new WebSocketConnectHandlerDecoratorFactory(this.eventPublisher);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,9 +22,8 @@ import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockitoAnnotations;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
@@ -45,16 +44,15 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class WebSocketRegistryListenerTests {
@Mock(lenient = true)
@Mock
private WebSocketSession wsSession;
@Mock(lenient = true)
@Mock
private WebSocketSession wsSession2;
@Mock(lenient = true)
@Mock
private Message<byte[]> message;
@Mock
@@ -76,6 +74,7 @@ class WebSocketRegistryListenerTests {
@BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
String sessionId = "session-id";
MapSession session = new MapSession(sessionId);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,14 +23,13 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import jakarta.servlet.http.HttpSession;
import javax.servlet.http.HttpSession;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockitoAnnotations;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.messaging.Message;
@@ -52,10 +51,9 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@ExtendWith(MockitoExtension.class)
class SessionRepositoryMessageInterceptorTests {
@Mock(lenient = true)
@Mock
SessionRepository<Session> sessionRepository;
@Mock
@@ -72,6 +70,7 @@ class SessionRepositoryMessageInterceptorTests {
@BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
this.interceptor = new SessionRepositoryMessageInterceptor<>(this.sessionRepository);
this.headers = SimpMessageHeaderAccessor.create();
this.headers.setSessionId("session");

View File

@@ -18,8 +18,6 @@ dependencies {
optional "org.mongodb:mongodb-driver-core"
testImplementation "org.mongodb:mongodb-driver-sync"
testImplementation "org.mongodb:mongodb-driver-reactivestreams"
testImplementation 'jakarta.websocket:jakarta.websocket-api'
testImplementation 'jakarta.websocket:jakarta.websocket-client-api'
integrationTestCompile "org.testcontainers:mongodb"
// Everything else
@@ -43,5 +41,5 @@ dependencies {
testImplementation "org.mockito:mockito-core"
testImplementation "org.mockito:mockito-junit-jupiter"
testImplementation "io.projectreactor:reactor-test"
testImplementation "jakarta.servlet:jakarta.servlet-api"
testImplementation "javax.servlet:javax.servlet-api"
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.session.data.mongo;
package org.springframework.session.data.mongo.integration;
import java.lang.reflect.Field;
@@ -25,6 +25,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.serializer.DefaultDeserializer;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
import org.springframework.session.data.mongo.Assert;
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
import org.springframework.util.ReflectionUtils;
/**
@@ -46,7 +49,8 @@ public abstract class AbstractClassLoaderTest<T> extends AbstractITest {
Field mongoSessionConverterField = ReflectionUtils.findField(this.sessionRepository.getClass(),
"mongoSessionConverter");
ReflectionUtils.makeAccessible(mongoSessionConverterField);
ReflectionUtils.makeAccessible(
Assert.requireNonNull(mongoSessionConverterField, "mongoSessionConverter must not be null!"));
AbstractMongoSessionConverter sessionConverter = (AbstractMongoSessionConverter) ReflectionUtils
.getField(mongoSessionConverterField, this.sessionRepository);
@@ -66,7 +70,7 @@ public abstract class AbstractClassLoaderTest<T> extends AbstractITest {
private static Object extractField(Class<?> clazz, String fieldName, Object obj) {
Field field = ReflectionUtils.findField(clazz, fieldName);
ReflectionUtils.makeAccessible(field);
ReflectionUtils.makeAccessible(Assert.requireNonNull(field, fieldName + " must not be null!"));
return ReflectionUtils.getField(field, obj);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.session.data.mongo;
package org.springframework.session.data.mongo.integration;
import java.util.UUID;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.session.data.mongo;
package org.springframework.session.data.mongo.integration;
import java.time.Duration;
import java.time.Instant;
@@ -37,6 +37,8 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
import org.springframework.session.data.mongo.MongoSession;
import static org.assertj.core.api.Assertions.assertThat;
@@ -387,20 +389,18 @@ public abstract class AbstractMongoRepositoryITest extends AbstractITest {
protected static class BaseConfig {
private static final String DOCKER_IMAGE = "mongo:5.0.11";
private static final String DOCKER_IMAGE = "mongo:4.0.10";
@Bean
public MongoDBContainer mongoDbContainer() {
MongoDBContainer mongoDbContainer = new MongoDBContainer(DOCKER_IMAGE);
mongoDbContainer.start();
return mongoDbContainer;
@Bean(initMethod = "start", destroyMethod = "stop")
public MongoDBContainer mongoContainer() {
return new MongoDBContainer(DOCKER_IMAGE).withExposedPorts(27017);
}
@Bean
public MongoOperations mongoOperations(MongoDBContainer mongoContainer) {
MongoClient mongo = MongoClients
.create("mongodb://" + mongoContainer.getHost() + ":" + mongoContainer.getFirstMappedPort());
MongoClient mongo = MongoClients.create(
"mongodb://" + mongoContainer.getContainerIpAddress() + ":" + mongoContainer.getFirstMappedPort());
return new MongoTemplate(mongo, "test");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.session.data.mongo;
package org.springframework.session.data.mongo.integration;
import java.net.URI;
@@ -41,6 +41,8 @@ import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
import org.springframework.session.data.mongo.JacksonMongoSessionConverter;
import org.springframework.session.data.mongo.config.annotation.web.reactive.EnableMongoWebSession;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -135,7 +137,6 @@ public class MongoDbDeleteJacksonSessionVerificationTest {
}
@Configuration(proxyBeanMethods = false)
@EnableWebFluxSecurity
static class SecurityConfig {
@@ -155,8 +156,9 @@ public class MongoDbDeleteJacksonSessionVerificationTest {
@Bean
MapReactiveUserDetailsService userDetailsService() {
return new MapReactiveUserDetailsService(User.withUsername("admin") //
.password("{noop}password") //
return new MapReactiveUserDetailsService(User.withDefaultPasswordEncoder() //
.username("admin") //
.password("password") //
.roles("USER,ADMIN") //
.build());
}
@@ -173,20 +175,18 @@ public class MongoDbDeleteJacksonSessionVerificationTest {
@EnableMongoWebSession
static class Config {
private static final String DOCKER_IMAGE = "mongo:5.0.11";
private static final String DOCKER_IMAGE = "mongo:4.0.10";
@Bean
MongoDBContainer mongoDbContainer() {
MongoDBContainer mongoDbContainer = new MongoDBContainer(DOCKER_IMAGE);
mongoDbContainer.start();
return mongoDbContainer;
@Bean(initMethod = "start", destroyMethod = "stop")
MongoDBContainer mongoContainer() {
return new MongoDBContainer(DOCKER_IMAGE).withExposedPorts(27017);
}
@Bean
ReactiveMongoOperations mongoOperations(MongoDBContainer mongoContainer) {
MongoClient mongo = MongoClients
.create("mongodb://" + mongoContainer.getHost() + ":" + mongoContainer.getFirstMappedPort());
MongoClient mongo = MongoClients.create(
"mongodb://" + mongoContainer.getContainerIpAddress() + ":" + mongoContainer.getFirstMappedPort());
return new ReactiveMongoTemplate(mongo, "DB_Name_DeleteJacksonSessionVerificationTest");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.session.data.mongo;
package org.springframework.session.data.mongo.integration;
import java.net.URI;
@@ -135,7 +135,6 @@ public class MongoDbLogoutVerificationTest {
}
@Configuration(proxyBeanMethods = false)
@EnableWebFluxSecurity
static class SecurityConfig {
@@ -157,8 +156,9 @@ public class MongoDbLogoutVerificationTest {
@Bean
MapReactiveUserDetailsService userDetailsService() {
return new MapReactiveUserDetailsService(User.withUsername("admin") //
.password("{noop}password") //
return new MapReactiveUserDetailsService(User.withDefaultPasswordEncoder() //
.username("admin") //
.password("password") //
.roles("USER,ADMIN") //
.build());
}
@@ -170,20 +170,18 @@ public class MongoDbLogoutVerificationTest {
@EnableMongoWebSession
static class Config {
private static final String DOCKER_IMAGE = "mongo:5.0.11";
private static final String DOCKER_IMAGE = "mongo:4.0.10";
@Bean
MongoDBContainer mongoDbContainer() {
MongoDBContainer mongoDbContainer = new MongoDBContainer(DOCKER_IMAGE);
mongoDbContainer.start();
return mongoDbContainer;
@Bean(initMethod = "start", destroyMethod = "stop")
MongoDBContainer mongoContainer() {
return new MongoDBContainer(DOCKER_IMAGE).withExposedPorts(27017);
}
@Bean
ReactiveMongoOperations mongoOperations(MongoDBContainer mongoContainer) {
MongoClient mongo = MongoClients
.create("mongodb://" + mongoContainer.getHost() + ":" + mongoContainer.getFirstMappedPort());
MongoClient mongo = MongoClients.create(
"mongodb://" + mongoContainer.getContainerIpAddress() + ":" + mongoContainer.getFirstMappedPort());
return new ReactiveMongoTemplate(mongo, "test");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.session.data.mongo;
package org.springframework.session.data.mongo.integration;
import java.util.Collections;
import java.util.Map;
@@ -25,6 +25,9 @@ import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.geo.GeoModule;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
import org.springframework.session.data.mongo.JacksonMongoSessionConverter;
import org.springframework.session.data.mongo.MongoSession;
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
import org.springframework.test.context.ContextConfiguration;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.session.data.mongo;
package org.springframework.session.data.mongo.integration;
import java.time.Duration;
import java.util.Map;
@@ -23,6 +23,9 @@ import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
import org.springframework.session.data.mongo.MongoSession;
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
import org.springframework.test.context.ContextConfiguration;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,8 +36,6 @@ import org.springframework.session.DelegatingIndexResolver;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.IndexResolver;
import org.springframework.session.PrincipalNameIndexResolver;
import org.springframework.session.Session;
import org.springframework.util.Assert;
/**
* Base class for serializing and deserializing session objects. To create custom
@@ -56,7 +54,8 @@ public abstract class AbstractMongoSessionConverter implements GenericConverter
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
private IndexResolver<Session> indexResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>());
private IndexResolver<MongoSession> indexResolver = new DelegatingIndexResolver<>(
new PrincipalNameIndexResolver<>());
/**
* Returns query to be executed to return sessions based on a particular index.
@@ -123,9 +122,8 @@ public abstract class AbstractMongoSessionConverter implements GenericConverter
protected abstract MongoSession convert(Document sessionWrapper);
public void setIndexResolver(IndexResolver<Session> indexResolver) {
Assert.notNull(indexResolver, "indexResolver must not be null");
this.indexResolver = indexResolver;
public void setIndexResolver(IndexResolver<MongoSession> indexResolver) {
this.indexResolver = Assert.requireNonNull(indexResolver, "indexResolver must not be null!");
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.mongo;
import org.springframework.lang.Nullable;
/**
* Utility to verify non null fields.
*
* @author Greg Turnquist
*/
public final class Assert {
private Assert() {
}
public static <T> T requireNonNull(@Nullable T item, String message) {
if (item == null) {
throw new IllegalArgumentException(message);
}
return item;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.apache.commons.logging.Log;
@@ -168,18 +168,18 @@ public class JacksonMongoSessionConverter extends AbstractMongoSessionConverter
}
private static class MongoIdNamingStrategy extends PropertyNamingStrategies.NamingBase {
private static class MongoIdNamingStrategy extends PropertyNamingStrategy.PropertyNamingStrategyBase {
@Override
public String translate(String propertyName) {
switch (propertyName) {
case "id":
return "_id";
case "_id":
return "id";
default:
return propertyName;
case "id":
return "_id";
case "_id":
return "id";
default:
return propertyName;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import com.mongodb.DBObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.Document;
@@ -35,11 +34,9 @@ import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.lang.Nullable;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.MapSession;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.util.Assert;
/**
* Session repository implementation which stores sessions in Mongo. Uses
@@ -49,7 +46,6 @@ import org.springframework.util.Assert;
*
* @author Jakub Kubrynski
* @author Greg Turnquist
* @author Vedran Pavic
* @since 2.2.0
*/
public class MongoIndexedSessionRepository
@@ -57,11 +53,8 @@ public class MongoIndexedSessionRepository
/**
* The default time period in seconds in which a session will expire.
* @deprecated since 3.0.0 in favor of
* {@link MapSession#DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS}
*/
@Deprecated
public static final int DEFAULT_INACTIVE_INTERVAL = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
public static final int DEFAULT_INACTIVE_INTERVAL = 1800;
/**
* the default collection name for storing session.
@@ -72,12 +65,12 @@ public class MongoIndexedSessionRepository
private final MongoOperations mongoOperations;
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
private Integer maxInactiveIntervalInSeconds = DEFAULT_INACTIVE_INTERVAL;
private String collectionName = DEFAULT_COLLECTION_NAME;
private AbstractMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(
this.defaultMaxInactiveInterval);
Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
private ApplicationEventPublisher eventPublisher;
@@ -90,7 +83,9 @@ public class MongoIndexedSessionRepository
MongoSession session = new MongoSession();
session.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
if (this.maxInactiveIntervalInSeconds != null) {
session.setMaxInactiveInterval(Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
}
publishEvent(new SessionCreatedEvent(this, session));
@@ -99,9 +94,9 @@ public class MongoIndexedSessionRepository
@Override
public void save(MongoSession session) {
DBObject dbObject = MongoSessionUtils.convertToDBObject(this.mongoSessionConverter, session);
Assert.notNull(dbObject, "dbObject must not be null");
this.mongoOperations.save(dbObject, this.collectionName);
this.mongoOperations
.save(Assert.requireNonNull(MongoSessionUtils.convertToDBObject(this.mongoSessionConverter, session),
"convertToDBObject must not null!"), this.collectionName);
}
@Override
@@ -183,29 +178,8 @@ public class MongoIndexedSessionRepository
}
}
/**
* Set the maximum inactive interval in seconds between requests before newly created
* sessions will be invalidated. A negative time indicates that the session will never
* time out. The default is 30 minutes.
* @param defaultMaxInactiveInterval the default maxInactiveInterval
*/
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
org.springframework.util.Assert.notNull(defaultMaxInactiveInterval,
"defaultMaxInactiveInterval must not be null");
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
}
/**
* Set the maximum inactive interval in seconds between requests before newly created
* sessions will be invalidated. A negative time indicates that the session will never
* time out. The default is 1800 (30 minutes).
* @param defaultMaxInactiveInterval the default maxInactiveInterval in seconds
* @deprecated since 3.0.0, in favor of
* {@link #setDefaultMaxInactiveInterval(Duration)}
*/
@Deprecated(since = "3.0.0")
public void setMaxInactiveIntervalInSeconds(Integer defaultMaxInactiveInterval) {
setDefaultMaxInactiveInterval(Duration.ofSeconds(defaultMaxInactiveInterval));
public void setMaxInactiveIntervalInSeconds(final Integer maxInactiveIntervalInSeconds) {
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
}
public void setCollectionName(final String collectionName) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,24 +14,23 @@
* limitations under the License.
*/
package org.springframework.session.mongodb.examples.mvc;
package org.springframework.session.data.mongo;
import java.security.Principal;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.data.mongodb.core.MongoOperations;
/**
* {@link ControllerAdvice} to expose user related attributes.
* This {@link org.springframework.session.FindByIndexNameSessionRepository}
* implementation is kept to support backwards compatibility.
*
* @author Rob Winch
* @since 1.2
* @deprecated since 2.2.0 in favor of {@link MongoIndexedSessionRepository}.
*/
@ControllerAdvice
public class UserControllerAdvise {
@Deprecated
public class MongoOperationsSessionRepository extends MongoIndexedSessionRepository {
@ModelAttribute("currentUserName")
String currentUser(Principal principal) {
return (principal != null) ? principal.getName() : null;
public MongoOperationsSessionRepository(MongoOperations mongoOperations) {
super(mongoOperations);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@ import java.util.UUID;
import java.util.stream.Collectors;
import org.springframework.lang.Nullable;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
/**
@@ -37,20 +36,13 @@ import org.springframework.session.Session;
* @author Greg Turnquist
* @since 1.2
*/
class MongoSession implements Session {
public class MongoSession implements Session {
/**
* Mongo doesn't support {@literal dot} in field names. We replace it with a unicode
* character from the Private Use Area.
* <p>
* NOTE: This was originally stored in unicode format. Delomboking the code caused it
* to get converted to another encoding, which isn't supported on all systems, so we
* migrated back to unicode. The same character is being represented ensuring binary
* compatibility.
*
* See https://www.compart.com/en/unicode/U+F607
* Mongo doesn't support {@literal dot} in field names. We replace it with a very
* rarely used character
*/
private static final char DOT_COVER_CHAR = '\uF607';
private static final char DOT_COVER_CHAR = '';
private String id;
@@ -66,15 +58,15 @@ class MongoSession implements Session {
private Map<String, Object> attrs = new HashMap<>();
MongoSession() {
this(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
public MongoSession() {
this(MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL);
}
MongoSession(long maxInactiveIntervalInSeconds) {
public MongoSession(long maxInactiveIntervalInSeconds) {
this(UUID.randomUUID().toString(), maxInactiveIntervalInSeconds);
}
MongoSession(String id, long maxInactiveIntervalInSeconds) {
public MongoSession(String id, long maxInactiveIntervalInSeconds) {
this.id = id;
this.originalSessionId = id;
@@ -130,7 +122,7 @@ class MongoSession implements Session {
return Instant.ofEpochMilli(this.createdMillis);
}
void setCreationTime(long created) {
public void setCreationTime(long created) {
this.createdMillis = created;
}
@@ -184,11 +176,11 @@ class MongoSession implements Session {
return this.id;
}
Date getExpireAt() {
public Date getExpireAt() {
return this.expireAt;
}
void setExpireAt(final Date expireAt) {
public void setExpireAt(final Date expireAt) {
this.expireAt = expireAt;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@ import org.springframework.lang.Nullable;
*
* @author Greg Turnquist
*/
final class MongoSessionUtils {
public final class MongoSessionUtils {
private MongoSessionUtils() {
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.mongo;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.session.ReactiveSessionRepository;
/**
* This {@link ReactiveSessionRepository} implementation is kept to support migration to
* {@link ReactiveMongoSessionRepository} in a backwards compatible manner.
*
* @author Greg Turnquist
* @deprecated since 2.2.0 in favor of {@link ReactiveMongoSessionRepository}.
*/
@Deprecated
public class ReactiveMongoOperationsSessionRepository extends ReactiveMongoSessionRepository {
public ReactiveMongoOperationsSessionRepository(ReactiveMongoOperations mongoOperations) {
super(mongoOperations);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,17 +32,14 @@ import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.session.MapSession;
import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.util.Assert;
/**
* A {@link ReactiveSessionRepository} implementation that uses Spring Data MongoDB.
*
* @author Greg Turnquist
* @author Vedran Pavic
* @since 2.2.0
*/
public class ReactiveMongoSessionRepository
@@ -50,11 +47,8 @@ public class ReactiveMongoSessionRepository
/**
* The default time period in seconds in which a session will expire.
* @deprecated since 3.0.0 in favor of
* {@link MapSession#DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS}
*/
@Deprecated
public static final int DEFAULT_INACTIVE_INTERVAL = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
public static final int DEFAULT_INACTIVE_INTERVAL = 1800;
/**
* The default collection name for storing session.
@@ -65,12 +59,12 @@ public class ReactiveMongoSessionRepository
private final ReactiveMongoOperations mongoOperations;
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
private Integer maxInactiveIntervalInSeconds = DEFAULT_INACTIVE_INTERVAL;
private String collectionName = DEFAULT_COLLECTION_NAME;
private AbstractMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(
this.defaultMaxInactiveInterval);
Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
private MongoOperations blockingMongoOperations;
@@ -94,7 +88,7 @@ public class ReactiveMongoSessionRepository
@Override
public Mono<MongoSession> createSession() {
return Mono.justOrEmpty(this.defaultMaxInactiveInterval.toSeconds()) //
return Mono.justOrEmpty(this.maxInactiveIntervalInSeconds) //
.map(MongoSession::new) //
.doOnNext((mongoSession) -> publishEvent(new SessionCreatedEvent(this, mongoSession))) //
.switchIfEmpty(Mono.just(new MongoSession()));
@@ -176,28 +170,12 @@ public class ReactiveMongoSessionRepository
}
}
/**
* Set the maximum inactive interval in seconds between requests before newly created
* sessions will be invalidated. A negative time indicates that the session will never
* time out. The default is 30 minutes.
* @param defaultMaxInactiveInterval the default maxInactiveInterval
*/
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
public Integer getMaxInactiveIntervalInSeconds() {
return this.maxInactiveIntervalInSeconds;
}
/**
* Set the maximum inactive interval in seconds between requests before newly created
* sessions will be invalidated. A negative time indicates that the session will never
* time out. The default is 1800 (30 minutes).
* @param defaultMaxInactiveInterval the default maxInactiveInterval in seconds
* @deprecated since 3.0.0, in favor of
* {@link #setDefaultMaxInactiveInterval(Duration)}
*/
@Deprecated(since = "3.0.0")
public void setMaxInactiveIntervalInSeconds(Integer defaultMaxInactiveInterval) {
setDefaultMaxInactiveInterval(Duration.ofSeconds(defaultMaxInactiveInterval));
public void setMaxInactiveIntervalInSeconds(final Integer maxInactiveIntervalInSeconds) {
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
}
public String getCollectionName() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,8 +22,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.session.MapSession;
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
/**
@@ -34,7 +34,6 @@ import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
*
* <pre>
* <code>
* {@literal @Configuration(proxyBeanMethods = false)}
* {@literal @EnableMongoHttpSession}
* public class MongoHttpSessionConfig {
*
@@ -53,13 +52,14 @@ import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
@Target(ElementType.TYPE)
@Documented
@Import(MongoHttpSessionConfiguration.class)
@Configuration(proxyBeanMethods = false)
public @interface EnableMongoHttpSession {
/**
* The maximum time a session will be kept if it is inactive.
* @return default max inactive interval in seconds
*/
int maxInactiveIntervalInSeconds() default MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
int maxInactiveIntervalInSeconds() default MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL;
/**
* The collection name to use.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.serializer.support.DeserializingConverter;
@@ -34,13 +33,12 @@ import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.session.IndexResolver;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.config.SessionRepositoryCustomizer;
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
import org.springframework.session.data.mongo.MongoSession;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;
@@ -53,12 +51,12 @@ import org.springframework.util.StringValueResolver;
* @since 1.2
*/
@Configuration(proxyBeanMethods = false)
@Import(SpringHttpSessionConfiguration.class)
public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguration
implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
private AbstractMongoSessionConverter mongoSessionConverter;
private Duration maxInactiveInterval = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL;
private Integer maxInactiveIntervalInSeconds;
private String collectionName;
@@ -68,13 +66,13 @@ public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, Embe
private ClassLoader classLoader;
private IndexResolver<Session> indexResolver;
private IndexResolver<MongoSession> indexResolver;
@Bean
public MongoIndexedSessionRepository mongoSessionRepository(MongoOperations mongoOperations) {
MongoIndexedSessionRepository repository = new MongoIndexedSessionRepository(mongoOperations);
repository.setDefaultMaxInactiveInterval(this.maxInactiveInterval);
repository.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds);
if (this.mongoSessionConverter != null) {
repository.setMongoSessionConverter(this.mongoSessionConverter);
@@ -86,7 +84,7 @@ public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, Embe
else {
JdkMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(new SerializingConverter(),
new DeserializingConverter(this.classLoader),
Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
Duration.ofSeconds(MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL));
if (this.indexResolver != null) {
mongoSessionConverter.setIndexResolver(this.indexResolver);
@@ -109,13 +107,8 @@ public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, Embe
this.collectionName = collectionName;
}
public void setMaxInactiveInterval(Duration maxInactiveInterval) {
this.maxInactiveInterval = maxInactiveInterval;
}
@Deprecated
public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) {
setMaxInactiveInterval(Duration.ofSeconds(maxInactiveIntervalInSeconds));
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
}
public void setImportMetadata(AnnotationMetadata importMetadata) {
@@ -124,8 +117,10 @@ public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, Embe
.fromMap(importMetadata.getAnnotationAttributes(EnableMongoHttpSession.class.getName()));
if (attributes != null) {
this.maxInactiveInterval = Duration
.ofSeconds(attributes.<Integer>getNumber("maxInactiveIntervalInSeconds"));
this.maxInactiveIntervalInSeconds = attributes.getNumber("maxInactiveIntervalInSeconds");
}
else {
this.maxInactiveIntervalInSeconds = MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL;
}
String collectionNameValue = (attributes != null) ? attributes.getString("collectionName") : "";
@@ -156,7 +151,7 @@ public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, Embe
}
@Autowired(required = false)
public void setIndexResolver(IndexResolver<Session> indexResolver) {
public void setIndexResolver(IndexResolver<MongoSession> indexResolver) {
this.indexResolver = indexResolver;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.session.MapSession;
import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
/**
@@ -32,7 +32,7 @@ import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
*
* <pre>
* <code>
* {@literal @Configuration(proxyBeanMethods = false)}
* {@literal @Configuration}
* {@literal @EnableMongoWebSession}
* public class SpringWebFluxConfig {
*
@@ -45,20 +45,21 @@ import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
* </code> </pre>
*
* @author Greg Turnquist
* @author Vedran Pavic
* @author Vedran Pavić
* @since 2.0
*/
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ java.lang.annotation.ElementType.TYPE })
@Documented
@Import(ReactiveMongoWebSessionConfiguration.class)
@Configuration(proxyBeanMethods = false)
public @interface EnableMongoWebSession {
/**
* The maximum time a session will be kept if it is inactive.
* @return default max inactive interval in seconds
*/
int maxInactiveIntervalInSeconds() default MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
int maxInactiveIntervalInSeconds() default ReactiveMongoSessionRepository.DEFAULT_INACTIVE_INTERVAL;
/**
* The collection name to use.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 the original author or authors.
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.serializer.support.DeserializingConverter;
@@ -35,12 +34,11 @@ import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.session.IndexResolver;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.config.ReactiveSessionRepositoryCustomizer;
import org.springframework.session.config.annotation.web.server.SpringWebSessionConfiguration;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
import org.springframework.session.data.mongo.MongoSession;
import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;
@@ -50,16 +48,15 @@ import org.springframework.util.StringValueResolver;
* {@link ReactiveMongoOperations}.
*
* @author Greg Turnquist
* @author Vedran Pavic
* @author Vedran Pavić
*/
@Configuration(proxyBeanMethods = false)
@Import(SpringWebSessionConfiguration.class)
public class ReactiveMongoWebSessionConfiguration
public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfiguration
implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
private AbstractMongoSessionConverter mongoSessionConverter;
private Duration maxInactiveInterval = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL;
private Integer maxInactiveIntervalInSeconds;
private String collectionName;
@@ -72,7 +69,7 @@ public class ReactiveMongoWebSessionConfiguration
private ClassLoader classLoader;
private IndexResolver<Session> indexResolver;
private IndexResolver<MongoSession> indexResolver;
@Bean
public ReactiveMongoSessionRepository reactiveMongoSessionRepository(ReactiveMongoOperations operations) {
@@ -90,7 +87,7 @@ public class ReactiveMongoWebSessionConfiguration
else {
JdkMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(new SerializingConverter(),
new DeserializingConverter(this.classLoader),
Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
Duration.ofSeconds(ReactiveMongoSessionRepository.DEFAULT_INACTIVE_INTERVAL));
if (this.indexResolver != null) {
mongoSessionConverter.setIndexResolver(this.indexResolver);
@@ -99,7 +96,9 @@ public class ReactiveMongoWebSessionConfiguration
repository.setMongoSessionConverter(mongoSessionConverter);
}
repository.setDefaultMaxInactiveInterval(this.maxInactiveInterval);
if (this.maxInactiveIntervalInSeconds != null) {
repository.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds);
}
if (this.collectionName != null) {
repository.setCollectionName(this.collectionName);
@@ -127,8 +126,10 @@ public class ReactiveMongoWebSessionConfiguration
.fromMap(importMetadata.getAnnotationAttributes(EnableMongoWebSession.class.getName()));
if (attributes != null) {
this.maxInactiveInterval = Duration
.ofSeconds(attributes.<Integer>getNumber("maxInactiveIntervalInSeconds"));
this.maxInactiveIntervalInSeconds = attributes.getNumber("maxInactiveIntervalInSeconds");
}
else {
this.maxInactiveIntervalInSeconds = ReactiveMongoSessionRepository.DEFAULT_INACTIVE_INTERVAL;
}
String collectionNameValue = (attributes != null) ? attributes.getString("collectionName") : "";
@@ -148,17 +149,12 @@ public class ReactiveMongoWebSessionConfiguration
this.embeddedValueResolver = embeddedValueResolver;
}
public Duration getMaxInactiveInterval() {
return this.maxInactiveInterval;
public Integer getMaxInactiveIntervalInSeconds() {
return this.maxInactiveIntervalInSeconds;
}
public void setMaxInactiveInterval(Duration maxInactiveInterval) {
this.maxInactiveInterval = maxInactiveInterval;
}
@Deprecated
public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) {
setMaxInactiveInterval(Duration.ofSeconds(maxInactiveIntervalInSeconds));
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
}
public String getCollectionName() {
@@ -176,7 +172,7 @@ public class ReactiveMongoWebSessionConfiguration
}
@Autowired(required = false)
public void setIndexResolver(IndexResolver<Session> indexResolver) {
public void setIndexResolver(IndexResolver<MongoSession> indexResolver) {
this.indexResolver = indexResolver;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ public abstract class AbstractMongoSessionConverterTest {
MongoSession deserialized = convertToSession(dbObject);
// then
assertThat(deserialized).usingRecursiveComparison().isEqualTo(toSerialize);
assertThat(deserialized).isEqualToComparingFieldByField(toSerialize);
}
@Test
@@ -67,12 +67,14 @@ public abstract class AbstractMongoSessionConverterTest {
MongoSession deserialized = convertToSession(serialized);
// then
assertThat(deserialized).usingRecursiveComparison().isEqualTo(toSerialize);
assertThat(deserialized).isEqualToComparingOnlyGivenFields(toSerialize, "id", "createdMillis", "accessedMillis",
"intervalSeconds", "expireAt");
SecurityContextImpl springSecurityContextBefore = toSerialize.getAttribute("SPRING_SECURITY_CONTEXT");
SecurityContextImpl springSecurityContextAfter = deserialized.getAttribute("SPRING_SECURITY_CONTEXT");
assertThat(springSecurityContextBefore).usingRecursiveComparison().isEqualTo(springSecurityContextAfter);
assertThat(springSecurityContextBefore).isEqualToComparingOnlyGivenFields(springSecurityContextAfter,
"authentication.principal", "authentication.authorities", "authentication.authenticated");
assertThat(springSecurityContextAfter.getAuthentication().getPrincipal()).isEqualTo("john_the_springer");
assertThat(springSecurityContextAfter.getAuthentication().getCredentials()).isNull();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@ import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.MapSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -77,7 +76,20 @@ public class MongoIndexedSessionRepositoryTest {
// then
assertThat(session.getId()).isNotEmpty();
assertThat(session.getMaxInactiveInterval().getSeconds())
.isEqualTo(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
.isEqualTo(MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL);
}
@Test
void shouldCreateSessionWhenMaxInactiveIntervalNotDefined() {
// when
this.repository.setMaxInactiveIntervalInSeconds(null);
MongoSession session = this.repository.createSession();
// then
assertThat(session.getId()).isNotEmpty();
assertThat(session.getMaxInactiveInterval().getSeconds())
.isEqualTo(MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL);
}
@Test
@@ -152,7 +164,8 @@ public class MongoIndexedSessionRepositoryTest {
Document sessionDocument = new Document();
sessionDocument.put("id", sessionId);
MongoSession mongoSession = new MongoSession(sessionId, MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
MongoSession mongoSession = new MongoSession(sessionId,
MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL);
given(this.converter.convert(sessionDocument, TypeDescriptor.valueOf(Document.class),
TypeDescriptor.valueOf(MongoSession.class))).willReturn(mongoSession);

Some files were not shown because too many files have changed in this diff Show More