Compare commits
6 Commits
2.1.0.M2
...
2.0.5.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7c2e8e79c | ||
|
|
6bec95a298 | ||
|
|
9249a140c9 | ||
|
|
7f6dc801e0 | ||
|
|
83d46ad685 | ||
|
|
21cef2b7fa |
99
Jenkinsfile
vendored
99
Jenkinsfile
vendored
@@ -1,9 +1,9 @@
|
||||
properties([
|
||||
buildDiscarder(logRotator(numToKeepStr: '10')),
|
||||
pipelineTriggers([
|
||||
cron('@daily')
|
||||
]),
|
||||
])
|
||||
def projectProperties = [
|
||||
[$class: 'BuildDiscarderProperty',
|
||||
strategy: [$class: 'LogRotator', numToKeepStr: '5']],
|
||||
pipelineTriggers([cron('@daily')])
|
||||
]
|
||||
properties(projectProperties)
|
||||
|
||||
def SUCCESS = hudson.model.Result.SUCCESS.toString()
|
||||
currentBuild.result = SUCCESS
|
||||
@@ -11,44 +11,49 @@ currentBuild.result = SUCCESS
|
||||
try {
|
||||
parallel check: {
|
||||
stage('Check') {
|
||||
timeout(time: 30, unit: 'MINUTES') {
|
||||
node {
|
||||
checkout scm
|
||||
try {
|
||||
sh './gradlew clean check --no-daemon --refresh-dependencies'
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: check'
|
||||
throw e
|
||||
}
|
||||
finally {
|
||||
junit '**/build/*-results/*.xml'
|
||||
}
|
||||
node {
|
||||
checkout scm
|
||||
try {
|
||||
sh "./gradlew clean check --refresh-dependencies --no-daemon"
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: check'
|
||||
throw e
|
||||
} finally {
|
||||
junit '**/build/*-results/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
springio: {
|
||||
stage('Spring IO') {
|
||||
node {
|
||||
checkout scm
|
||||
try {
|
||||
sh "./gradlew clean springIoCheck -PplatformVersion=Cairo-BUILD-SNAPSHOT -PexcludeProjects='**/samples/**' --refresh-dependencies --no-daemon --stacktrace"
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: springio'
|
||||
throw e
|
||||
} finally {
|
||||
junit '**/build/spring-io*-results/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentBuild.result == 'SUCCESS') {
|
||||
if(currentBuild.result == 'SUCCESS') {
|
||||
parallel artifacts: {
|
||||
stage('Deploy Artifacts') {
|
||||
node {
|
||||
checkout scm
|
||||
try {
|
||||
withCredentials([file(credentialsId: 'spring-signing-secring.gpg', variable: 'SIGNING_KEYRING_FILE')]) {
|
||||
withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) {
|
||||
withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) {
|
||||
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
|
||||
sh './gradlew deployArtifacts finalizeDeployArtifacts --stacktrace --no-daemon --refresh-dependencies -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password=$SIGNING_PASSWORD -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD'
|
||||
}
|
||||
withCredentials([file(credentialsId: 'spring-signing-secring.gpg', variable: 'SIGNING_KEYRING_FILE')]) {
|
||||
withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) {
|
||||
withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) {
|
||||
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
|
||||
sh "./gradlew deployArtifacts finalizeDeployArtifacts -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password='$SIGNING_PASSWORD' -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --refresh-dependencies --no-daemon --stacktrace"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: artifacts'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -56,38 +61,32 @@ try {
|
||||
stage('Deploy Docs') {
|
||||
node {
|
||||
checkout scm
|
||||
try {
|
||||
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
|
||||
sh './gradlew deployDocs --stacktrace --no-daemon --refresh-dependencies -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: docs'
|
||||
throw e
|
||||
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
|
||||
sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
def buildStatus = currentBuild.result
|
||||
def buildNotSuccess = !SUCCESS.equals(buildStatus)
|
||||
def buildNotSuccess = !SUCCESS.equals(buildStatus)
|
||||
def lastBuildNotSuccess = !SUCCESS.equals(currentBuild.previousBuild?.result)
|
||||
|
||||
if (buildNotSuccess || lastBuildNotSuccess) {
|
||||
stage('Notify') {
|
||||
if(buildNotSuccess || lastBuildNotSuccess) {
|
||||
|
||||
stage('Notifiy') {
|
||||
node {
|
||||
final def RECIPIENTS = [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']]
|
||||
|
||||
def subject = "${buildStatus}: Build ${env.JOB_NAME} ${env.BUILD_NUMBER} status is now ${buildStatus}"
|
||||
def details = "The build status changed to ${buildStatus}. For details see ${env.BUILD_URL}"
|
||||
def details = """The build status changed to ${buildStatus}. For details see ${env.BUILD_URL}"""
|
||||
|
||||
emailext(
|
||||
subject: subject,
|
||||
body: details,
|
||||
recipientProviders: RECIPIENTS,
|
||||
to: "$SPRING_SESSION_TEAM_EMAILS"
|
||||
emailext (
|
||||
subject: subject,
|
||||
body: details,
|
||||
recipientProviders: RECIPIENTS,
|
||||
to: "$SPRING_SESSION_TEAM_EMAILS"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,10 +614,9 @@ Spring Session's most basic API for using a `Session` is the `SessionRepository`
|
||||
This API is intentionally very simple, so that it is easy to provide additional implementations with basic functionality.
|
||||
|
||||
Some `SessionRepository` implementations may choose to implement `FindByIndexNameSessionRepository` also.
|
||||
For example, Spring's Redis, JDBC and Hazelcast support all implement `FindByIndexNameSessionRepository`.
|
||||
For example, Spring's Redis support implements `FindByIndexNameSessionRepository`.
|
||||
|
||||
The `FindByIndexNameSessionRepository` provides a method to look up all the sessions with a given index name and index value.
|
||||
As a common use case that is supported by all provided `FindByIndexNameSessionRepository` implementations, there's a convenient method to look up all the sessions for a particular user.
|
||||
The `FindByIndexNameSessionRepository` adds a single method to look up all the sessions for a particular user.
|
||||
This is done by ensuring that the session attribute with the name `FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME` is populated with the username.
|
||||
It is the responsibility of the developer to ensure the attribute is populated since Spring Session is not aware of the authentication mechanism being used.
|
||||
An example of how this might be used can be seen below:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -52,7 +52,9 @@ public class FindByIndexNameSessionRepositoryTests {
|
||||
// tag::findby-username[]
|
||||
String username = "username";
|
||||
Map<String, Session> sessionIdToSession = this.sessionRepository
|
||||
.findByPrincipalName(username);
|
||||
.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
|
||||
username);
|
||||
// end::findby-username[]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -43,7 +43,6 @@ import static org.springframework.security.test.web.servlet.setup.SecurityMockMv
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = RememberMeSecurityConfiguration.class)
|
||||
@@ -87,6 +86,5 @@ public class RememberMeSecurityConfigurationTests<T extends Session> {
|
||||
.isEqualTo(Duration.ofDays(30));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -43,7 +43,6 @@ import static org.springframework.security.test.web.servlet.setup.SecurityMockMv
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@@ -87,6 +86,5 @@ public class RememberMeSecurityConfigurationXmlTests<T extends Session> {
|
||||
.isEqualTo(Duration.ofDays(30));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
springBootVersion=2.1.0.M1
|
||||
version=2.1.0.M2
|
||||
springBootVersion=2.0.3.RELEASE
|
||||
version=2.0.5.RELEASE
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.6'
|
||||
mavenBom 'io.projectreactor:reactor-bom:Californium-M2'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.1.0.RC2'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Lovelace-RC2'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.1.0.RC1'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.8.3'
|
||||
mavenBom 'io.projectreactor:reactor-bom:Bismuth-SR10'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.0.8.RELEASE'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-SR9'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.0.7.RELEASE'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.8.1'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dependencySet(group: 'com.hazelcast', version: '3.10.4') {
|
||||
dependencySet(group: 'com.hazelcast', version: '3.9.4') {
|
||||
entry 'hazelcast'
|
||||
entry 'hazelcast-client'
|
||||
}
|
||||
|
||||
dependency 'com.h2database:h2:1.4.197'
|
||||
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.0.0.jre8'
|
||||
dependency 'com.microsoft.sqlserver:mssql-jdbc:6.4.0.jre8'
|
||||
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
|
||||
dependency 'io.lettuce:lettuce-core:5.1.0.M1'
|
||||
dependency 'javax.annotation:javax.annotation-api:1.3.2'
|
||||
dependency 'javax.servlet:javax.servlet-api:4.0.1'
|
||||
dependency 'io.lettuce:lettuce-core:5.0.4.RELEASE'
|
||||
dependency 'javax.servlet:javax.servlet-api:3.1.0'
|
||||
dependency 'junit:junit:4.12'
|
||||
dependency 'mysql:mysql-connector-java:8.0.12'
|
||||
dependency 'mysql:mysql-connector-java:8.0.11'
|
||||
dependency 'org.apache.derby:derby:10.14.2.0'
|
||||
dependency 'org.assertj:assertj-core:3.11.0'
|
||||
dependency 'org.assertj:assertj-core:3.10.0'
|
||||
dependency 'org.hsqldb:hsqldb:2.4.1'
|
||||
dependency 'org.mariadb.jdbc:mariadb-java-client:2.2.6'
|
||||
dependency 'org.mockito:mockito-core:2.21.0'
|
||||
dependency 'org.mockito:mockito-core:2.20.1'
|
||||
dependency 'org.postgresql:postgresql:42.2.4'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
|
||||
public class FindByUsernameTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -44,7 +44,10 @@ public class IndexController {
|
||||
@RequestMapping("/")
|
||||
public String index(Principal principal, Model model) {
|
||||
Collection<? extends Session> usersSessions = this.sessions
|
||||
.findByPrincipalName(principal.getName()).values();
|
||||
.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
|
||||
principal.getName())
|
||||
.values();
|
||||
model.addAttribute("sessions", usersSessions);
|
||||
return "index";
|
||||
}
|
||||
@@ -53,8 +56,9 @@ public class IndexController {
|
||||
@RequestMapping(value = "/sessions/{sessionIdToDelete}", method = RequestMethod.DELETE)
|
||||
public String removeSession(Principal principal,
|
||||
@PathVariable String sessionIdToDelete) {
|
||||
Set<String> usersSessionIds = this.sessions
|
||||
.findByPrincipalName(principal.getName()).keySet();
|
||||
Set<String> usersSessionIds = this.sessions.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
|
||||
principal.getName()).keySet();
|
||||
if (usersSessionIds.contains(sessionIdToDelete)) {
|
||||
this.sessions.deleteById(sessionIdToDelete);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -34,7 +34,6 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@AutoConfigureMockMvc
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -36,7 +36,7 @@ public class LoginPage extends BasePage {
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Please sign in");
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
|
||||
}
|
||||
|
||||
public Form form() {
|
||||
@@ -51,7 +51,7 @@ public class LoginPage extends BasePage {
|
||||
@FindBy(name = "password")
|
||||
private WebElement password;
|
||||
|
||||
@FindBy(tagName = "button")
|
||||
@FindBy(name = "submit")
|
||||
private WebElement button;
|
||||
|
||||
public Form(SearchContext context) {
|
||||
|
||||
@@ -50,7 +50,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@AutoConfigureMockMvc
|
||||
public class HttpRedisJsonTest {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@SpringBootTest
|
||||
public class RedisSerializerTest {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@SpringSessionRedisOperations
|
||||
private RedisTemplate<Object, Object> sessionRedisTemplate;
|
||||
|
||||
@@ -45,7 +45,7 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
|
||||
public class BootTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -36,7 +36,7 @@ public class LoginPage extends BasePage {
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Please sign in");
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
|
||||
}
|
||||
|
||||
public Form form() {
|
||||
@@ -51,7 +51,7 @@ public class LoginPage extends BasePage {
|
||||
@FindBy(name = "password")
|
||||
private WebElement password;
|
||||
|
||||
@FindBy(tagName = "button")
|
||||
@FindBy(name = "submit")
|
||||
private WebElement button;
|
||||
|
||||
public Form(SearchContext context) {
|
||||
|
||||
@@ -47,7 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class AttributeTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@@ -52,7 +52,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class ApplicationTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private String port;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
ext['spring.version'] = '5.1.0.RC2'
|
||||
|
||||
dependencyManagement {
|
||||
dependencies {
|
||||
dependency 'ch.qos.logback:logback-classic:1.2.3'
|
||||
@@ -7,7 +5,7 @@ dependencyManagement {
|
||||
dependency 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1'
|
||||
dependency 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.2-b02'
|
||||
dependency 'org.apache.taglibs:taglibs-standard-jstlel:1.2.5'
|
||||
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.32.0'
|
||||
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.29.3'
|
||||
dependency 'org.slf4j:jcl-over-slf4j:1.7.25'
|
||||
dependency 'org.slf4j:log4j-over-slf4j:1.7.25'
|
||||
dependency 'org.webjars:bootstrap:2.3.2'
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -36,7 +36,7 @@ public class LoginPage extends BasePage {
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Please sign in");
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
|
||||
}
|
||||
|
||||
public Form form() {
|
||||
@@ -51,7 +51,7 @@ public class LoginPage extends BasePage {
|
||||
@FindBy(name = "password")
|
||||
private WebElement password;
|
||||
|
||||
@FindBy(tagName = "button")
|
||||
@FindBy(name = "submit")
|
||||
private WebElement button;
|
||||
|
||||
public Form(SearchContext context) {
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -54,7 +54,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@WebAppConfiguration
|
||||
public class RestMockMvcTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Autowired
|
||||
private SessionRepositoryFilter<? extends Session> sessionRepositoryFilter;
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -34,7 +34,7 @@ public class LoginPage extends BasePage {
|
||||
@FindBy(name = "password")
|
||||
private WebElement password;
|
||||
|
||||
@FindBy(tagName = "button")
|
||||
@FindBy(css = "input[type='submit']")
|
||||
private WebElement button;
|
||||
|
||||
public LoginPage(WebDriver driver) {
|
||||
@@ -47,7 +47,7 @@ public class LoginPage extends BasePage {
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Please sign in");
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
|
||||
}
|
||||
|
||||
public HomePage login(String user, String password) {
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -6,7 +6,6 @@ dependencies {
|
||||
compile "org.springframework:spring-jcl"
|
||||
|
||||
optional "io.projectreactor:reactor-core"
|
||||
optional "javax.annotation:javax.annotation-api"
|
||||
optional "javax.servlet:javax.servlet-api"
|
||||
optional "org.springframework:spring-context"
|
||||
optional "org.springframework:spring-jdbc"
|
||||
|
||||
@@ -19,22 +19,27 @@ package org.springframework.session;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Extends a basic {@link SessionRepository} to allow finding sessions by the specified
|
||||
* index name and index value.
|
||||
* Extends a basic {@link SessionRepository} to allow finding a session id by the
|
||||
* principal name. The principal name is defined by the {@link Session} attribute with the
|
||||
* name {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}.
|
||||
*
|
||||
* @param <S> the type of Session being managed by this
|
||||
* {@link FindByIndexNameSessionRepository}
|
||||
* @author Rob Winch
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
public interface FindByIndexNameSessionRepository<S extends Session>
|
||||
extends SessionRepository<S> {
|
||||
|
||||
/**
|
||||
* A session index that contains the current principal name (i.e. username).
|
||||
* <p>
|
||||
* It is the responsibility of the developer to ensure the index is populated since
|
||||
* Spring Session is not aware of the authentication mechanism being used.
|
||||
* A common session attribute that contains the current principal name (i.e.
|
||||
* username).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It is the responsibility of the developer to ensure the attribute is populated
|
||||
* since Spring Session is not aware of the authentication mechanism being used.
|
||||
* </p>
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
@@ -42,34 +47,17 @@ public interface FindByIndexNameSessionRepository<S extends Session>
|
||||
.concat(".PRINCIPAL_NAME_INDEX_NAME");
|
||||
|
||||
/**
|
||||
* Find a {@link Map} of the session id to the {@link Session} of all sessions that
|
||||
* contain the specified index name index value.
|
||||
* Find a Map of the session id to the {@link Session} of all sessions that contain
|
||||
* the session attribute with the name
|
||||
* {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME} and the value of
|
||||
* the specified principal name.
|
||||
*
|
||||
* @param indexName the name of the index (i.e.
|
||||
* {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME})
|
||||
* @param indexValue the value of the index to search for.
|
||||
* @return a {@code Map} (never {@code null}) of the session id to the {@code Session}
|
||||
* of all sessions that contain the specified index name and index value. If no
|
||||
* results are found, an empty {@code Map} is returned.
|
||||
* @return a Map (never null) of the session id to the {@link Session} of all sessions
|
||||
* that contain the session specified index name and the value of the specified index
|
||||
* name. If no results are found, an empty Map is returned.
|
||||
*/
|
||||
Map<String, S> findByIndexNameAndIndexValue(String indexName, String indexValue);
|
||||
|
||||
/**
|
||||
* Find a {@link Map} of the session id to the {@link Session} of all sessions that
|
||||
* contain the index with the name
|
||||
* {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME} and the
|
||||
* specified principal name.
|
||||
*
|
||||
* @param principalName the principal name
|
||||
* @return a {@code Map} (never {@code null}) of the session id to the {@code Session}
|
||||
* of all sessions that contain the specified principal name. If no results are found,
|
||||
* an empty {@code Map} is returned.
|
||||
* @since 2.1.0
|
||||
*/
|
||||
default Map<String, S> findByPrincipalName(String principalName) {
|
||||
|
||||
return findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principalName);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public final class MapSession implements Session, Serializable {
|
||||
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
|
||||
|
||||
private String id;
|
||||
private final String originalId;
|
||||
private String originalId;
|
||||
private Map<String, Object> sessionAttrs = new HashMap<>();
|
||||
private Instant creationTime = Instant.now();
|
||||
private Instant lastAccessedTime = this.creationTime;
|
||||
@@ -132,6 +132,10 @@ public final class MapSession implements Session, Serializable {
|
||||
return this.originalId;
|
||||
}
|
||||
|
||||
void setOriginalId(String originalId) {
|
||||
this.originalId = originalId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
String changedId = generateId();
|
||||
|
||||
@@ -73,6 +73,7 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
public void save(MapSession session) {
|
||||
if (!session.getId().equals(session.getOriginalId())) {
|
||||
this.sessions.remove(session.getOriginalId());
|
||||
session.setOriginalId(session.getId());
|
||||
}
|
||||
this.sessions.put(session.getId(), new MapSession(session));
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ public class ReactiveMapSessionRepository implements ReactiveSessionRepository<M
|
||||
return Mono.fromRunnable(() -> {
|
||||
if (!session.getId().equals(session.getOriginalId())) {
|
||||
this.sessions.remove(session.getOriginalId());
|
||||
session.setOriginalId(session.getId());
|
||||
}
|
||||
this.sessions.put(session.getId(), new MapSession(session));
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -65,8 +65,9 @@ public class SpringSessionBackedSessionRegistry<S extends Session>
|
||||
@Override
|
||||
public List<SessionInformation> getAllSessions(Object principal,
|
||||
boolean includeExpiredSessions) {
|
||||
Collection<S> sessions = this.sessionRepository
|
||||
.findByPrincipalName(name(principal)).values();
|
||||
Collection<S> sessions = this.sessionRepository.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
|
||||
name(principal)).values();
|
||||
List<SessionInformation> infos = new ArrayList<>();
|
||||
for (S session : sessions) {
|
||||
if (includeExpiredSessions || !Boolean.TRUE.equals(session
|
||||
|
||||
@@ -16,13 +16,8 @@
|
||||
|
||||
package org.springframework.session.web.http;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -46,22 +41,6 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DefaultCookieSerializer.class);
|
||||
|
||||
private static final BitSet domainValid = new BitSet(128);
|
||||
|
||||
static {
|
||||
for (char c = '0'; c <= '9'; c++) {
|
||||
domainValid.set(c);
|
||||
}
|
||||
for (char c = 'a'; c <= 'z'; c++) {
|
||||
domainValid.set(c);
|
||||
}
|
||||
for (char c = 'A'; c <= 'Z'; c++) {
|
||||
domainValid.set(c);
|
||||
}
|
||||
domainValid.set('.');
|
||||
domainValid.set('-');
|
||||
}
|
||||
|
||||
private String cookieName = "SESSION";
|
||||
|
||||
private Boolean useSecureCookie;
|
||||
@@ -82,8 +61,6 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
|
||||
private String rememberMeRequestAttribute;
|
||||
|
||||
private String sameSite = "Lax";
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -98,8 +75,7 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (this.cookieName.equals(cookie.getName())) {
|
||||
String sessionId = (this.useBase64Encoding
|
||||
? base64Decode(cookie.getValue())
|
||||
: cookie.getValue());
|
||||
? base64Decode(cookie.getValue()) : cookie.getValue());
|
||||
if (sessionId == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -125,43 +101,37 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
HttpServletRequest request = cookieValue.getRequest();
|
||||
HttpServletResponse response = cookieValue.getResponse();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.cookieName).append('=');
|
||||
String value = getValue(cookieValue);
|
||||
if (value != null && value.length() > 0) {
|
||||
validateValue(value);
|
||||
sb.append(value);
|
||||
}
|
||||
int maxAge = getMaxAge(cookieValue);
|
||||
if (maxAge > -1) {
|
||||
sb.append("; Max-Age=").append(cookieValue.getCookieMaxAge());
|
||||
OffsetDateTime expires = (maxAge != 0
|
||||
? OffsetDateTime.now().plusSeconds(maxAge)
|
||||
: Instant.EPOCH.atOffset(ZoneOffset.UTC));
|
||||
sb.append("; Expires=")
|
||||
.append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||
}
|
||||
String domain = getDomainName(request);
|
||||
if (domain != null && domain.length() > 0) {
|
||||
validateDomain(domain);
|
||||
sb.append("; Domain=").append(domain);
|
||||
}
|
||||
String path = getCookiePath(request);
|
||||
if (path != null && path.length() > 0) {
|
||||
validatePath(path);
|
||||
sb.append("; Path=").append(path);
|
||||
}
|
||||
if (isSecureCookie(request)) {
|
||||
sb.append("; Secure");
|
||||
}
|
||||
if (this.useHttpOnlyCookie) {
|
||||
sb.append("; HttpOnly");
|
||||
}
|
||||
if (this.sameSite != null) {
|
||||
sb.append("; SameSite=").append(this.sameSite);
|
||||
String requestedCookieValue = cookieValue.getCookieValue();
|
||||
String actualCookieValue = (this.jvmRoute != null
|
||||
? requestedCookieValue + this.jvmRoute : requestedCookieValue);
|
||||
|
||||
Cookie sessionCookie = new Cookie(this.cookieName, this.useBase64Encoding
|
||||
? base64Encode(actualCookieValue) : actualCookieValue);
|
||||
sessionCookie.setSecure(isSecureCookie(request));
|
||||
sessionCookie.setPath(getCookiePath(request));
|
||||
String domainName = getDomainName(request);
|
||||
if (domainName != null) {
|
||||
sessionCookie.setDomain(domainName);
|
||||
}
|
||||
|
||||
response.addHeader("Set-Cookie", sb.toString());
|
||||
if (this.useHttpOnlyCookie) {
|
||||
sessionCookie.setHttpOnly(true);
|
||||
}
|
||||
|
||||
if (cookieValue.getCookieMaxAge() < 0) {
|
||||
if (this.rememberMeRequestAttribute != null
|
||||
&& request.getAttribute(this.rememberMeRequestAttribute) != null) {
|
||||
// the cookie is only written at time of session creation, so we rely on
|
||||
// session expiration rather than cookie expiration if remember me is enabled
|
||||
cookieValue.setCookieMaxAge(Integer.MAX_VALUE);
|
||||
}
|
||||
else if (this.cookieMaxAge != null) {
|
||||
cookieValue.setCookieMaxAge(this.cookieMaxAge);
|
||||
}
|
||||
}
|
||||
sessionCookie.setMaxAge(cookieValue.getCookieMaxAge());
|
||||
|
||||
response.addCookie(sessionCookie);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,81 +162,6 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
return new String(encodedCookieBytes);
|
||||
}
|
||||
|
||||
private String getValue(CookieValue cookieValue) {
|
||||
String requestedCookieValue = cookieValue.getCookieValue();
|
||||
String actualCookieValue = requestedCookieValue;
|
||||
if (this.jvmRoute != null) {
|
||||
actualCookieValue = requestedCookieValue + this.jvmRoute;
|
||||
}
|
||||
if (this.useBase64Encoding) {
|
||||
actualCookieValue = base64Encode(actualCookieValue);
|
||||
}
|
||||
return actualCookieValue;
|
||||
}
|
||||
|
||||
private void validateValue(String value) {
|
||||
int start = 0;
|
||||
int end = value.length();
|
||||
if ((end > 1) && (value.charAt(0) == '"') && (value.charAt(end - 1) == '"')) {
|
||||
start = 1;
|
||||
end--;
|
||||
}
|
||||
char[] chars = value.toCharArray();
|
||||
for (int i = start; i < end; i++) {
|
||||
char c = chars[i];
|
||||
if (c < 0x21 || c == 0x22 || c == 0x2c || c == 0x3b || c == 0x5c
|
||||
|| c == 0x7f) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid character in cookie value: " + Integer.toString(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getMaxAge(CookieValue cookieValue) {
|
||||
int maxAge = cookieValue.getCookieMaxAge();
|
||||
if (maxAge < 0) {
|
||||
if (this.rememberMeRequestAttribute != null && cookieValue.getRequest()
|
||||
.getAttribute(this.rememberMeRequestAttribute) != null) {
|
||||
// the cookie is only written at time of session creation, so we rely on
|
||||
// session expiration rather than cookie expiration if remember me is
|
||||
// enabled
|
||||
cookieValue.setCookieMaxAge(Integer.MAX_VALUE);
|
||||
}
|
||||
else if (this.cookieMaxAge != null) {
|
||||
cookieValue.setCookieMaxAge(this.cookieMaxAge);
|
||||
}
|
||||
}
|
||||
return cookieValue.getCookieMaxAge();
|
||||
}
|
||||
|
||||
private void validateDomain(String domain) {
|
||||
int i = 0;
|
||||
int cur = -1;
|
||||
int prev;
|
||||
char[] chars = domain.toCharArray();
|
||||
while (i < chars.length) {
|
||||
prev = cur;
|
||||
cur = chars[i];
|
||||
if (!domainValid.get(cur)
|
||||
|| ((prev == '.' || prev == -1) && (cur == '.' || cur == '-'))
|
||||
|| (prev == '-' && cur == '.')) {
|
||||
throw new IllegalArgumentException("Invalid cookie domain: " + domain);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (cur == '.' || cur == '-') {
|
||||
throw new IllegalArgumentException("Invalid cookie domain: " + domain);
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePath(String path) {
|
||||
for (char ch : path.toCharArray()) {
|
||||
if (ch < 0x20 || ch > 0x7E || ch == ';') {
|
||||
throw new IllegalArgumentException("Invalid cookie path: " + path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if a Cookie marked as secure should be used. The default is to use the value
|
||||
* of {@link HttpServletRequest#isSecure()}.
|
||||
@@ -422,16 +317,6 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
this.rememberMeRequestAttribute = rememberMeRequestAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code SameSite} cookie directive. The default value is
|
||||
* {@code Lax}.
|
||||
* @param sameSite the SameSite directive value
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public void setSameSite(String sameSite) {
|
||||
this.sameSite = sameSite;
|
||||
}
|
||||
|
||||
private String getDomainName(HttpServletRequest request) {
|
||||
if (this.domainName != null) {
|
||||
return this.domainName;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -24,13 +24,8 @@ import java.util.Set;
|
||||
|
||||
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;
|
||||
|
||||
import org.springframework.session.Session;
|
||||
|
||||
/**
|
||||
@@ -38,14 +33,11 @@ import org.springframework.session.Session;
|
||||
*
|
||||
* @param <S> the {@link Session} type
|
||||
* @author Rob Winch
|
||||
* @author Vedran Pavic
|
||||
* @since 1.1
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(HttpSessionAdapter.class);
|
||||
|
||||
private S session;
|
||||
|
||||
private final ServletContext servletContext;
|
||||
@@ -137,28 +129,7 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
@Override
|
||||
public void setAttribute(String name, Object value) {
|
||||
checkState();
|
||||
Object oldValue = this.session.getAttribute(name);
|
||||
this.session.setAttribute(name, value);
|
||||
if (value != oldValue) {
|
||||
if (oldValue instanceof HttpSessionBindingListener) {
|
||||
try {
|
||||
((HttpSessionBindingListener) oldValue).valueUnbound(
|
||||
new HttpSessionBindingEvent(this, name, oldValue));
|
||||
}
|
||||
catch (Throwable th) {
|
||||
logger.error("Error invoking session binding event listener", th);
|
||||
}
|
||||
}
|
||||
if (value instanceof HttpSessionBindingListener) {
|
||||
try {
|
||||
((HttpSessionBindingListener) value)
|
||||
.valueBound(new HttpSessionBindingEvent(this, name, value));
|
||||
}
|
||||
catch (Throwable th) {
|
||||
logger.error("Error invoking session binding event listener", th);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,17 +140,7 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
checkState();
|
||||
Object oldValue = this.session.getAttribute(name);
|
||||
this.session.removeAttribute(name);
|
||||
if (oldValue instanceof HttpSessionBindingListener) {
|
||||
try {
|
||||
((HttpSessionBindingListener) oldValue)
|
||||
.valueUnbound(new HttpSessionBindingEvent(this, name, oldValue));
|
||||
}
|
||||
catch (Throwable th) {
|
||||
logger.error("Error invoking session binding event listener", th);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -87,6 +87,12 @@ public class SpringSessionWebSessionStore<S extends Session> implements WebSessi
|
||||
return Mono.just(session);
|
||||
}
|
||||
|
||||
public Mono<Void> storeSession(WebSession session) {
|
||||
@SuppressWarnings("unchecked")
|
||||
SpringSessionWebSession springWebSession = (SpringSessionWebSession) session;
|
||||
return this.sessions.save(springWebSession.session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<WebSession> retrieveSession(String sessionId) {
|
||||
return this.sessions.findById(sessionId)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -162,8 +162,9 @@ public class SpringSessionBackedSessionRegistryTest {
|
||||
Map<String, Session> sessions = new LinkedHashMap<>();
|
||||
sessions.put(session1.getId(), session1);
|
||||
sessions.put(session2.getId(), session2);
|
||||
when(this.sessionRepository.findByPrincipalName(USER_NAME))
|
||||
.thenReturn(sessions);
|
||||
when(this.sessionRepository.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, USER_NAME))
|
||||
.thenReturn(sessions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.springframework.mock.web.MockCookie;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.session.web.http.CookieSerializer.CookieValue;
|
||||
@@ -467,39 +466,6 @@ public class DefaultCookieSerializerTests {
|
||||
assertThat(getCookie().getMaxAge()).isEqualTo(100);
|
||||
}
|
||||
|
||||
// --- sameSite ---
|
||||
|
||||
@Test
|
||||
public void writeCookieDefaultSameSiteLax() {
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSameSite()).isEqualTo("Lax");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeCookieSetSameSiteLax() {
|
||||
this.serializer.setSameSite("Lax");
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSameSite()).isEqualTo("Lax");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeCookieSetSameSiteStrict() {
|
||||
this.serializer.setSameSite("Strict");
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSameSite()).isEqualTo("Strict");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeCookieSetSameSiteNull() {
|
||||
this.serializer.setSameSite(null);
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSameSite()).isNull();
|
||||
}
|
||||
|
||||
public void setCookieName(String cookieName) {
|
||||
this.cookieName = cookieName;
|
||||
this.serializer.setCookieName(cookieName);
|
||||
@@ -512,8 +478,8 @@ public class DefaultCookieSerializerTests {
|
||||
return new Cookie(name, value);
|
||||
}
|
||||
|
||||
private MockCookie getCookie() {
|
||||
return (MockCookie) this.response.getCookie(this.cookieName);
|
||||
private Cookie getCookie() {
|
||||
return this.response.getCookie(this.cookieName);
|
||||
}
|
||||
|
||||
private String getCookieValue() {
|
||||
|
||||
@@ -27,8 +27,6 @@ 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 javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletContext;
|
||||
@@ -38,8 +36,6 @@ 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;
|
||||
@@ -1390,122 +1386,6 @@ public class SessionRepositoryFilterTests {
|
||||
.hasMessage("httpSessionIdResolver cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindListener() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindListenerThenUnbind() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
session.removeAttribute(bindingListenerName);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindSameListenerTwice() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindListenerOverwrite() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener1 = new CountingHttpSessionBindingListener();
|
||||
CountingHttpSessionBindingListener bindingListener2 = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener1);
|
||||
session.setAttribute(bindingListenerName, bindingListener2);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener1.getCounter()).isEqualTo(0);
|
||||
assertThat(bindingListener2.getCounter()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindThrowsException() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
bindingListener.setThrowException();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindListenerThenUnbindThrowsException() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
bindingListener.setThrowException();
|
||||
session.removeAttribute(bindingListenerName);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(1);
|
||||
}
|
||||
|
||||
// --- helper methods
|
||||
|
||||
private void assertNewSession() {
|
||||
@@ -1608,39 +1488,4 @@ public class SessionRepositoryFilterTests {
|
||||
|
||||
}
|
||||
|
||||
private static class CountingHttpSessionBindingListener
|
||||
implements HttpSessionBindingListener {
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger(0);
|
||||
|
||||
private final AtomicBoolean throwException = new AtomicBoolean(false);
|
||||
|
||||
@Override
|
||||
public void valueBound(HttpSessionBindingEvent event) {
|
||||
if (this.throwException.get()) {
|
||||
this.throwException.compareAndSet(true, false);
|
||||
throw new RuntimeException("bind exception");
|
||||
}
|
||||
this.counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueUnbound(HttpSessionBindingEvent event) {
|
||||
if (this.throwException.get()) {
|
||||
this.throwException.compareAndSet(true, false);
|
||||
throw new RuntimeException("unbind exception");
|
||||
}
|
||||
this.counter.decrementAndGet();
|
||||
}
|
||||
|
||||
int getCounter() {
|
||||
return this.counter.get();
|
||||
}
|
||||
|
||||
void setThrowException() {
|
||||
this.throwException.compareAndSet(false, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -253,6 +253,17 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
.containsExactly(new AbstractMap.SimpleEntry<>(attrName, attrValue));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void storeSessionWhenInvokedThenSessionSaved() {
|
||||
given(this.sessionRepository.save(this.createSession)).willReturn(Mono.empty());
|
||||
WebSession createdSession = this.webSessionStore.createWebSession()
|
||||
.block();
|
||||
|
||||
this.webSessionStore.storeSession(createdSession).block();
|
||||
|
||||
verify(this.sessionRepository).save(this.createSession);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveSessionThenStarted() {
|
||||
String id = "id";
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
*/
|
||||
public abstract class AbstractRedisITests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.11";
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.10";
|
||||
|
||||
protected static class BaseConfig {
|
||||
|
||||
|
||||
@@ -118,10 +118,6 @@ public class ReactiveRedisOperationsSessionRepository implements
|
||||
this.redisFlushMode = redisFlushMode;
|
||||
}
|
||||
|
||||
public ReactiveRedisOperations<String, Object> getSessionRedisOperations() {
|
||||
return this.sessionRedisOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<RedisSession> createSession() {
|
||||
return Mono.defer(() -> {
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.Map;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -65,8 +64,6 @@ public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
|
||||
|
||||
private ReactiveRedisConnectionFactory redisConnectionFactory;
|
||||
|
||||
private RedisSerializer<Object> defaultRedisSerializer;
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
@@ -110,13 +107,6 @@ public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
|
||||
this.redisConnectionFactory = redisConnectionFactoryToUse;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
@Qualifier("springSessionDefaultRedisSerializer")
|
||||
public void setDefaultRedisSerializer(
|
||||
RedisSerializer<Object> defaultRedisSerializer) {
|
||||
this.defaultRedisSerializer = defaultRedisSerializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
@@ -144,11 +134,10 @@ public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
|
||||
|
||||
private ReactiveRedisTemplate<String, Object> createReactiveRedisTemplate() {
|
||||
RedisSerializer<String> keySerializer = new StringRedisSerializer();
|
||||
RedisSerializer<Object> defaultSerializer = (this.defaultRedisSerializer != null
|
||||
? this.defaultRedisSerializer
|
||||
: new JdkSerializationRedisSerializer(this.classLoader));
|
||||
RedisSerializer<Object> valueSerializer = new JdkSerializationRedisSerializer(
|
||||
this.classLoader);
|
||||
RedisSerializationContext<String, Object> serializationContext = RedisSerializationContext
|
||||
.<String, Object>newSerializationContext(defaultSerializer)
|
||||
.<String, Object>newSerializationContext(valueSerializer)
|
||||
.key(keySerializer).hashKey(keySerializer).build();
|
||||
return new ReactiveRedisTemplate<>(this.redisConnectionFactory,
|
||||
serializationContext);
|
||||
|
||||
@@ -27,12 +27,9 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.ReactiveRedisOperations;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.session.data.redis.ReactiveRedisOperationsSessionRepository;
|
||||
import org.springframework.session.data.redis.RedisFlushMode;
|
||||
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisConnectionFactory;
|
||||
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisOperations;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -73,22 +70,6 @@ public class RedisWebSessionConfigurationTests {
|
||||
assertThat(repository).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void springSessionRedisOperationsResolvingConfiguration() {
|
||||
registerAndRefresh(RedisConfig.class,
|
||||
SpringSessionRedisOperationsResolvingConfig.class);
|
||||
|
||||
ReactiveRedisOperationsSessionRepository repository = this.context
|
||||
.getBean(ReactiveRedisOperationsSessionRepository.class);
|
||||
assertThat(repository).isNotNull();
|
||||
ReactiveRedisOperations<String, Object> springSessionRedisOperations = this.context
|
||||
.getBean(SpringSessionRedisOperationsResolvingConfig.class)
|
||||
.getSpringSessionRedisOperations();
|
||||
assertThat(springSessionRedisOperations).isNotNull();
|
||||
assertThat((ReactiveRedisOperations) ReflectionTestUtils.getField(repository,
|
||||
"sessionRedisOperations")).isEqualTo(springSessionRedisOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customNamespace() {
|
||||
registerAndRefresh(RedisConfig.class, CustomNamespaceConfig.class);
|
||||
@@ -200,36 +181,6 @@ public class RedisWebSessionConfigurationTests {
|
||||
.hasMessageContaining("expected single matching bean but found 2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void customRedisSerializerConfig() {
|
||||
registerAndRefresh(RedisConfig.class, CustomRedisSerializerConfig.class);
|
||||
|
||||
ReactiveRedisOperationsSessionRepository repository = this.context
|
||||
.getBean(ReactiveRedisOperationsSessionRepository.class);
|
||||
RedisSerializer<Object> redisSerializer = this.context
|
||||
.getBean("springSessionDefaultRedisSerializer", RedisSerializer.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(redisSerializer).isNotNull();
|
||||
ReactiveRedisOperations redisOperations = (ReactiveRedisOperations) ReflectionTestUtils
|
||||
.getField(repository, "sessionRedisOperations");
|
||||
assertThat(redisOperations).isNotNull();
|
||||
RedisSerializationContext serializationContext = redisOperations
|
||||
.getSerializationContext();
|
||||
assertThat(ReflectionTestUtils.getField(
|
||||
serializationContext.getValueSerializationPair().getReader(),
|
||||
"serializer")).isEqualTo(redisSerializer);
|
||||
assertThat(ReflectionTestUtils.getField(
|
||||
serializationContext.getValueSerializationPair().getWriter(),
|
||||
"serializer")).isEqualTo(redisSerializer);
|
||||
assertThat(ReflectionTestUtils.getField(
|
||||
serializationContext.getHashValueSerializationPair().getReader(),
|
||||
"serializer")).isEqualTo(redisSerializer);
|
||||
assertThat(ReflectionTestUtils.getField(
|
||||
serializationContext.getHashValueSerializationPair().getWriter(),
|
||||
"serializer")).isEqualTo(redisSerializer);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
@@ -250,18 +201,6 @@ public class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableRedisWebSession
|
||||
static class SpringSessionRedisOperationsResolvingConfig {
|
||||
|
||||
@SpringSessionRedisOperations
|
||||
private ReactiveRedisOperations<String, Object> springSessionRedisOperations;
|
||||
|
||||
public ReactiveRedisOperations<String, Object> getSpringSessionRedisOperations() {
|
||||
return this.springSessionRedisOperations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableRedisWebSession(redisNamespace = REDIS_NAMESPACE)
|
||||
static class CustomNamespaceConfig {
|
||||
|
||||
@@ -336,15 +275,4 @@ public class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableRedisWebSession
|
||||
static class CustomRedisSerializerConfig {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
|
||||
return mock(RedisSerializer.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
||||
public class HazelcastClientRepositoryITests extends AbstractHazelcastRepositoryITests {
|
||||
|
||||
private static GenericContainer container = new GenericContainer<>(
|
||||
"hazelcast/hazelcast:3.10.3")
|
||||
"hazelcast/hazelcast:3.9.4")
|
||||
.withExposedPorts(5701)
|
||||
.withEnv("JAVA_OPTS",
|
||||
"-Dhazelcast.config=/opt/hazelcast/config_ext/hazelcast.xml")
|
||||
|
||||
@@ -743,31 +743,6 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
assertThat(session.<String>getAttribute("testName")).isEqualTo("testValue2");
|
||||
}
|
||||
|
||||
@Test // gh-1031
|
||||
public void saveDeleted() {
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
|
||||
this.repository.save(session);
|
||||
session = this.repository.findById(session.getId());
|
||||
this.repository.deleteById(session.getId());
|
||||
session.setLastAccessedTime(Instant.now());
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.findById(session.getId())).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-1031
|
||||
public void saveDeletedAddAttribute() {
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
|
||||
this.repository.save(session);
|
||||
session = this.repository.findById(session.getId());
|
||||
this.repository.deleteById(session.getId());
|
||||
session.setLastAccessedTime(Instant.now());
|
||||
session.setAttribute("testName", "testValue1");
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.findById(session.getId())).isNull();
|
||||
}
|
||||
|
||||
private String getSecurityName() {
|
||||
return this.context.getAuthentication().getName();
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public class MariaDb10JdbcOperationsSessionRepositoryITests
|
||||
private static class MariaDb10Container extends MariaDBContainer<MariaDb10Container> {
|
||||
|
||||
MariaDb10Container() {
|
||||
super("mariadb:10.3.9");
|
||||
super("mariadb:10.3.8");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -86,7 +86,7 @@ public class MariaDb5JdbcOperationsSessionRepositoryITests
|
||||
private static class MariaDb5Container extends MariaDBContainer<MariaDb5Container> {
|
||||
|
||||
MariaDb5Container() {
|
||||
super("mariadb:5.5.61");
|
||||
super("mariadb:5.5.60");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -85,7 +85,7 @@ public class MySql5JdbcOperationsSessionRepositoryITests
|
||||
private static class MySql5Container extends MySQLContainer<MySql5Container> {
|
||||
|
||||
MySql5Container() {
|
||||
super("mysql:5.7.23");
|
||||
super("mysql:5.7.22");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -85,7 +85,7 @@ public class MySql8JdbcOperationsSessionRepositoryITests
|
||||
private static class MySql8Container extends MySQLContainer<MySql8Container> {
|
||||
|
||||
MySql8Container() {
|
||||
super("mysql:8.0.12");
|
||||
super("mysql:8.0.11");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -86,7 +86,7 @@ public class PostgreSql10JdbcOperationsSessionRepositoryITests
|
||||
extends PostgreSQLContainer<PostgreSql10Container> {
|
||||
|
||||
PostgreSql10Container() {
|
||||
super("postgres:10.5");
|
||||
super("postgres:10.4");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public class PostgreSql9JdbcOperationsSessionRepositoryITests
|
||||
extends PostgreSQLContainer<PostgreSql9Container> {
|
||||
|
||||
PostgreSql9Container() {
|
||||
super("postgres:9.6.10");
|
||||
super("postgres:9.6.9");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public class SqlServerJdbcOperationsSessionRepositoryITests
|
||||
extends MSSQLServerContainer<SqlServer2007Container> {
|
||||
|
||||
SqlServer2007Container() {
|
||||
super("microsoft/mssql-server-linux:2017-CU9");
|
||||
super("microsoft/mssql-server-linux:2017-CU8");
|
||||
withStartupTimeoutSeconds(240);
|
||||
withConnectTimeoutSeconds(240);
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
microsoft/mssql-server-linux:2017-CU9
|
||||
microsoft/mssql-server-linux:2017-CU8
|
||||
|
||||
@@ -52,9 +52,7 @@ import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionOperations;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
@@ -146,9 +144,7 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
private static final String CREATE_SESSION_ATTRIBUTE_QUERY =
|
||||
"INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " +
|
||||
"SELECT PRIMARY_ID, ?, ? " +
|
||||
"FROM %TABLE_NAME% " +
|
||||
"WHERE SESSION_ID = ?";
|
||||
"VALUES (?, ?, ?)";
|
||||
|
||||
private static final String GET_SESSION_QUERY =
|
||||
"SELECT S.PRIMARY_ID, S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " +
|
||||
@@ -191,17 +187,10 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
private final JdbcOperations jdbcOperations;
|
||||
|
||||
private final TransactionOperations transactionOperations;
|
||||
|
||||
private final ResultSetExtractor<List<JdbcSession>> extractor = new SessionResultSetExtractor();
|
||||
|
||||
private TransactionOperations transactionOperations = new TransactionOperations() {
|
||||
|
||||
@Override
|
||||
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
|
||||
return action.doInTransaction(null);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The name of database table used by Spring Session to store sessions.
|
||||
*/
|
||||
@@ -238,29 +227,14 @@ public class JdbcOperationsSessionRepository implements
|
||||
/**
|
||||
* Create a new {@link JdbcOperationsSessionRepository} instance which uses the
|
||||
* provided {@link JdbcOperations} to manage sessions.
|
||||
* <p>
|
||||
* The created instance will execute all data access operations in a transaction with
|
||||
* propagation level of {@link TransactionDefinition#PROPAGATION_REQUIRES_NEW}.
|
||||
* @param jdbcOperations the {@link JdbcOperations} to use
|
||||
* @param transactionManager the {@link PlatformTransactionManager} to use
|
||||
*/
|
||||
public JdbcOperationsSessionRepository(JdbcOperations jdbcOperations,
|
||||
PlatformTransactionManager transactionManager) {
|
||||
this(jdbcOperations);
|
||||
Assert.notNull(transactionManager, "TransactionManager must not be null");
|
||||
this.transactionOperations = createTransactionTemplate(transactionManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link JdbcOperationsSessionRepository} instance which uses the
|
||||
* provided {@link JdbcOperations} to manage sessions.
|
||||
* <p>
|
||||
* The created instance will not execute data access operations in a transaction.
|
||||
* @param jdbcOperations the {@link JdbcOperations} to use
|
||||
*/
|
||||
public JdbcOperationsSessionRepository(JdbcOperations jdbcOperations) {
|
||||
Assert.notNull(jdbcOperations, "JdbcOperations must not be null");
|
||||
this.jdbcOperations = jdbcOperations;
|
||||
this.transactionOperations = createTransactionTemplate(transactionManager);
|
||||
this.conversionService = createDefaultConversionService();
|
||||
prepareQueries();
|
||||
}
|
||||
@@ -407,9 +381,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
ps.setLong(6, session.getExpiryTime().toEpochMilli());
|
||||
ps.setString(7, session.getPrincipalName());
|
||||
});
|
||||
Set<String> attributeNames = session.getAttributeNames();
|
||||
if (!attributeNames.isEmpty()) {
|
||||
insertSessionAttributes(session, new ArrayList<>(attributeNames));
|
||||
if (!session.getAttributeNames().isEmpty()) {
|
||||
final List<String> attributeNames = new ArrayList<>(session.getAttributeNames());
|
||||
insertSessionAttributes(session, attributeNames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,23 +410,17 @@ public class JdbcOperationsSessionRepository implements
|
||||
.filter((entry) -> entry.getValue() == DeltaValue.ADDED)
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
if (!addedAttributeNames.isEmpty()) {
|
||||
insertSessionAttributes(session, addedAttributeNames);
|
||||
}
|
||||
insertSessionAttributes(session, addedAttributeNames);
|
||||
List<String> updatedAttributeNames = session.delta.entrySet().stream()
|
||||
.filter((entry) -> entry.getValue() == DeltaValue.UPDATED)
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
if (!updatedAttributeNames.isEmpty()) {
|
||||
updateSessionAttributes(session, updatedAttributeNames);
|
||||
}
|
||||
updateSessionAttributes(session, updatedAttributeNames);
|
||||
List<String> removedAttributeNames = session.delta.entrySet().stream()
|
||||
.filter((entry) -> entry.getValue() == DeltaValue.REMOVED)
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
if (!removedAttributeNames.isEmpty()) {
|
||||
deleteSessionAttributes(session, removedAttributeNames);
|
||||
}
|
||||
deleteSessionAttributes(session, removedAttributeNames);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -522,16 +490,18 @@ public class JdbcOperationsSessionRepository implements
|
||||
}
|
||||
|
||||
private void insertSessionAttributes(JdbcSession session, List<String> attributeNames) {
|
||||
Assert.notEmpty(attributeNames, "attributeNames must not be null or empty");
|
||||
if (attributeNames == null || attributeNames.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (attributeNames.size() > 1) {
|
||||
this.jdbcOperations.batchUpdate(this.createSessionAttributeQuery, new BatchPreparedStatementSetter() {
|
||||
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
String attributeName = attributeNames.get(i);
|
||||
ps.setString(1, attributeName);
|
||||
serialize(ps, 2, session.getAttribute(attributeName));
|
||||
ps.setString(3, session.getId());
|
||||
ps.setString(1, session.primaryKey);
|
||||
ps.setString(2, attributeName);
|
||||
serialize(ps, 3, session.getAttribute(attributeName));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -544,15 +514,17 @@ public class JdbcOperationsSessionRepository implements
|
||||
else {
|
||||
this.jdbcOperations.update(this.createSessionAttributeQuery, (ps) -> {
|
||||
String attributeName = attributeNames.get(0);
|
||||
ps.setString(1, attributeName);
|
||||
serialize(ps, 2, session.getAttribute(attributeName));
|
||||
ps.setString(3, session.getId());
|
||||
ps.setString(1, session.primaryKey);
|
||||
ps.setString(2, attributeName);
|
||||
serialize(ps, 3, session.getAttribute(attributeName));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSessionAttributes(JdbcSession session, List<String> attributeNames) {
|
||||
Assert.notEmpty(attributeNames, "attributeNames must not be null or empty");
|
||||
if (attributeNames == null || attributeNames.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (attributeNames.size() > 1) {
|
||||
this.jdbcOperations.batchUpdate(this.updateSessionAttributeQuery, new BatchPreparedStatementSetter() {
|
||||
|
||||
@@ -582,7 +554,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
}
|
||||
|
||||
private void deleteSessionAttributes(JdbcSession session, List<String> attributeNames) {
|
||||
Assert.notEmpty(attributeNames, "attributeNames must not be null or empty");
|
||||
if (attributeNames == null || attributeNames.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (attributeNames.size() > 1) {
|
||||
this.jdbcOperations.batchUpdate(this.deleteSessionAttributeQuery, new BatchPreparedStatementSetter() {
|
||||
|
||||
|
||||
@@ -42,10 +42,7 @@ import org.springframework.transaction.TransactionDefinition;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.endsWith;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.ArgumentMatchers.startsWith;
|
||||
@@ -91,7 +88,7 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
assertThatThrownBy(
|
||||
() -> new JdbcOperationsSessionRepository(this.jdbcOperations, null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("TransactionManager must not be null");
|
||||
.hasMessage("Property 'transactionManager' is required");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -691,89 +688,6 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveNewWithoutTransaction() {
|
||||
this.repository = new JdbcOperationsSessionRepository(this.jdbcOperations);
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository
|
||||
.createSession();
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
verify(this.jdbcOperations, times(1)).update(
|
||||
startsWith("INSERT INTO SPRING_SESSION"),
|
||||
isA(PreparedStatementSetter.class));
|
||||
verifyZeroInteractions(this.jdbcOperations);
|
||||
verifyZeroInteractions(this.transactionManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveUpdatedWithoutTransaction() {
|
||||
this.repository = new JdbcOperationsSessionRepository(this.jdbcOperations);
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession(
|
||||
"primaryKey", new MapSession());
|
||||
session.setLastAccessedTime(Instant.now());
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
verify(this.jdbcOperations, times(1)).update(startsWith("UPDATE SPRING_SESSION"),
|
||||
isA(PreparedStatementSetter.class));
|
||||
verifyZeroInteractions(this.jdbcOperations);
|
||||
verifyZeroInteractions(this.transactionManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findByIdWithoutTransaction() {
|
||||
given(this.jdbcOperations.query(anyString(), any(PreparedStatementSetter.class),
|
||||
any(ResultSetExtractor.class))).willReturn(Collections.emptyList());
|
||||
this.repository = new JdbcOperationsSessionRepository(this.jdbcOperations);
|
||||
this.repository.findById("testSessionId");
|
||||
|
||||
verify(this.jdbcOperations, times(1)).query(endsWith("WHERE S.SESSION_ID = ?"),
|
||||
isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class));
|
||||
verifyZeroInteractions(this.jdbcOperations);
|
||||
verifyZeroInteractions(this.transactionManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteByIdWithoutTransaction() {
|
||||
this.repository = new JdbcOperationsSessionRepository(this.jdbcOperations);
|
||||
this.repository.deleteById("testSessionId");
|
||||
|
||||
verify(this.jdbcOperations, times(1)).update(
|
||||
eq("DELETE FROM SPRING_SESSION WHERE SESSION_ID = ?"), anyString());
|
||||
verifyZeroInteractions(this.jdbcOperations);
|
||||
verifyZeroInteractions(this.transactionManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findByIndexNameAndIndexValueWithoutTransaction() {
|
||||
given(this.jdbcOperations.query(anyString(), any(PreparedStatementSetter.class),
|
||||
any(ResultSetExtractor.class))).willReturn(Collections.emptyList());
|
||||
this.repository = new JdbcOperationsSessionRepository(this.jdbcOperations);
|
||||
this.repository.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
|
||||
"testIndexValue");
|
||||
|
||||
verify(this.jdbcOperations, times(1)).query(
|
||||
endsWith("WHERE S.PRINCIPAL_NAME = ?"),
|
||||
isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class));
|
||||
verifyZeroInteractions(this.jdbcOperations);
|
||||
verifyZeroInteractions(this.transactionManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cleanUpExpiredSessionsWithoutTransaction() {
|
||||
this.repository = new JdbcOperationsSessionRepository(this.jdbcOperations);
|
||||
this.repository.cleanUpExpiredSessions();
|
||||
|
||||
verify(this.jdbcOperations, times(1)).update(
|
||||
eq("DELETE FROM SPRING_SESSION WHERE EXPIRY_TIME < ?"), anyLong());
|
||||
verifyZeroInteractions(this.jdbcOperations);
|
||||
verifyZeroInteractions(this.transactionManager);
|
||||
}
|
||||
|
||||
private void assertPropagationRequiresNew() {
|
||||
ArgumentCaptor<TransactionDefinition> argument =
|
||||
ArgumentCaptor.forClass(TransactionDefinition.class);
|
||||
|
||||
Reference in New Issue
Block a user