Compare commits
30 Commits
1.3.2.RELE
...
1.3.5.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
774e6df063 | ||
|
|
6911bd359b | ||
|
|
ddae03c79e | ||
|
|
bba095f276 | ||
|
|
61937a9251 | ||
|
|
3885b7e7ff | ||
|
|
bea569c3c8 | ||
|
|
7f1434cc4c | ||
|
|
cd8f87e0a9 | ||
|
|
95f41a7024 | ||
|
|
d245cc1a36 | ||
|
|
695f2f1509 | ||
|
|
3940a22d5e | ||
|
|
eb4ce12915 | ||
|
|
46bac131d0 | ||
|
|
9675278729 | ||
|
|
f0c216d9d5 | ||
|
|
cb6f7fdfa6 | ||
|
|
b50a4e247e | ||
|
|
6b3d78ac09 | ||
|
|
c0bd38c46f | ||
|
|
2262600b21 | ||
|
|
0c11a4297a | ||
|
|
b778d97dc7 | ||
|
|
d0887fe40d | ||
|
|
1a94d742b1 | ||
|
|
c433b01ee5 | ||
|
|
a3195f1f4b | ||
|
|
467ecaaeff | ||
|
|
4a18242d95 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -10,5 +10,5 @@ target
|
||||
out
|
||||
.springBeans
|
||||
*.rdb
|
||||
!eclispe/.checkstyle
|
||||
.checkstyle
|
||||
.checkstyle
|
||||
!etc/eclipse/.checkstyle
|
||||
|
||||
@@ -19,7 +19,7 @@ plugins {
|
||||
|
||||
group = 'org.springframework.session'
|
||||
|
||||
ext.springBootVersion = '1.4.2.RELEASE'
|
||||
ext.springBootVersion = '1.4.7.RELEASE'
|
||||
ext.IDE_GRADLE = "$rootDir/gradle/ide.gradle"
|
||||
ext.JAVA_GRADLE = "$rootDir/gradle/java.gradle"
|
||||
ext.SPRING3_GRADLE = "$rootDir/gradle/spring3.gradle"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -22,7 +22,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.session.MapSessionRepository;
|
||||
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
|
||||
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
|
||||
@@ -52,7 +51,7 @@ public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapte
|
||||
|
||||
// tag::rememberme-bean[]
|
||||
@Bean
|
||||
RememberMeServices rememberMeServices() {
|
||||
public SpringSessionRememberMeServices rememberMeServices() {
|
||||
SpringSessionRememberMeServices rememberMeServices =
|
||||
new SpringSessionRememberMeServices();
|
||||
// optionally customize
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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 org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
|
||||
|
||||
@@ -33,7 +32,7 @@ import org.springframework.session.security.SpringSessionBackedSessionRegistry;
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
FindByIndexNameSessionRepository<ExpiringSession> sessionRepository;
|
||||
private FindByIndexNameSessionRepository sessionRepository;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
@@ -45,7 +44,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpringSessionBackedSessionRegistry sessionRegistry() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public SpringSessionBackedSessionRegistry sessionRegistry() {
|
||||
return new SpringSessionBackedSessionRegistry(this.sessionRepository);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ cleanup_profile=_Spring Boot Cleanup Conventions
|
||||
cleanup_settings_version=2
|
||||
eclipse.preferences.version=1
|
||||
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
|
||||
formatter_profile=_Spring Boot Java Conventions
|
||||
formatter_profile=Spring Session Java Conventions
|
||||
formatter_settings_version=12
|
||||
org.eclipse.jdt.ui.exception.name=e
|
||||
org.eclipse.jdt.ui.gettersetter.use.is=true
|
||||
@@ -1,11 +1,11 @@
|
||||
bootstrapVersion=2.3.2
|
||||
commonsPoolVersion=2.4.2
|
||||
jacksonVersion=2.6.5
|
||||
jacksonVersion=2.8.8
|
||||
jspApiVersion=2.0
|
||||
servletApiVersion=3.0.1
|
||||
jstlelVersion=1.2.5
|
||||
version=1.3.2.RELEASE
|
||||
springDataRedisVersion=1.7.10.RELEASE
|
||||
version=1.3.5.RELEASE
|
||||
springDataRedisVersion=1.7.11.RELEASE
|
||||
html5ShivVersion=3.7.3
|
||||
commonsLoggingVersion=1.2
|
||||
junitVersion=4.12
|
||||
@@ -13,19 +13,19 @@ springDataRedisSpring3Version=1.7.1.RELEASE
|
||||
lettuceVersion=3.5.0.Final
|
||||
gebVersion=0.13.1
|
||||
mockitoVersion=1.10.19
|
||||
hazelcastVersion=3.6.5
|
||||
hazelcastVersion=3.6.8
|
||||
seleniumVersion=2.52.0
|
||||
springDataGeodeVersion=1.0.0.INCUBATING-RELEASE
|
||||
springSecurityVersion=4.2.0.RELEASE
|
||||
springVersion=4.3.4.RELEASE
|
||||
httpClientVersion=4.5.1
|
||||
h2Version=1.4.192
|
||||
jedisVersion=2.8.1
|
||||
springDataMongoVersion=1.9.4.RELEASE
|
||||
springSecurityVersion=4.2.11.RELEASE
|
||||
springVersion=4.3.19.RELEASE
|
||||
httpClientVersion=4.5.3
|
||||
h2Version=1.4.195
|
||||
jedisVersion=2.8.2
|
||||
springDataMongoVersion=1.9.11.RELEASE
|
||||
springShellVersion=1.1.0.RELEASE
|
||||
springDataGemFireVersion=1.8.10.RELEASE
|
||||
springDataGemFireVersion=1.8.11.RELEASE
|
||||
assertjVersion=2.5.0
|
||||
spockVersion=1.0-groovy-2.4
|
||||
webjarsTaglibVersion=0.3
|
||||
jstlVersion=1.2.1
|
||||
groovyVersion=2.4.4
|
||||
groovyVersion=2.4.11
|
||||
|
||||
@@ -78,7 +78,7 @@ task integrationTest(type: Test, dependsOn: jar) {
|
||||
check.dependsOn integrationTest
|
||||
|
||||
checkstyle {
|
||||
configFile = rootProject.file('config/checkstyle/checkstyle.xml')
|
||||
configFile = rootProject.file('etc/checkstyle/checkstyle.xml')
|
||||
configProperties.configDir = configFile.parentFile
|
||||
toolVersion = '6.16.1'
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session'),
|
||||
"org.springframework.boot:spring-boot-starter-data-redis",
|
||||
|
||||
@@ -14,6 +14,8 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session'),
|
||||
"org.springframework.boot:spring-boot-starter-data-redis",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -42,7 +42,8 @@ public class SessionConfig {
|
||||
int port = SocketUtils.findAvailableTcpPort();
|
||||
|
||||
config.getNetworkConfig()
|
||||
.setPort(port);
|
||||
.setPort(port)
|
||||
.getJoin().getMulticastConfig().setEnabled(false);
|
||||
|
||||
System.out.println("Hazelcast port #: " + port);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -52,6 +52,7 @@ public class Initializer implements ServletContextListener {
|
||||
Config cfg = new Config();
|
||||
NetworkConfig netConfig = new NetworkConfig();
|
||||
netConfig.setPort(getAvailablePort());
|
||||
netConfig.getJoin().getMulticastConfig().setEnabled(false);
|
||||
cfg.setNetworkConfig(netConfig);
|
||||
SerializerConfig serializer = new SerializerConfig().setTypeClass(Object.class)
|
||||
.setImplementation(new ObjectStreamSerializer());
|
||||
|
||||
@@ -12,6 +12,8 @@ apply plugin: "application"
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply from: SAMPLE_GRADLE
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-data-gemfire'),
|
||||
"org.springframework.boot:spring-boot-starter-thymeleaf",
|
||||
@@ -19,14 +21,14 @@ dependencies {
|
||||
"org.webjars:bootstrap:$bootstrapVersion",
|
||||
"org.webjars:webjars-locator"
|
||||
|
||||
runtime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
runtime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
integrationTestCompile gebDependencies,
|
||||
"org.spockframework:spock-spring:$spockVersion"
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
run {
|
||||
|
||||
@@ -12,13 +12,13 @@ dependencies {
|
||||
|
||||
providedCompile "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
|
||||
runtime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
runtime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
|
||||
testCompile "junit:junit:$junitVersion"
|
||||
|
||||
integrationTestCompile gebDependencies
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
mainClassName = 'sample.Application'
|
||||
|
||||
@@ -12,13 +12,13 @@ dependencies {
|
||||
|
||||
providedCompile "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
|
||||
runtime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
runtime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
|
||||
testCompile "junit:junit:$junitVersion"
|
||||
|
||||
integrationTestCompile gebDependencies
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,5 +15,5 @@ dependencies {
|
||||
|
||||
integrationTestCompile gebDependencies
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
@@ -15,5 +15,5 @@ dependencies {
|
||||
|
||||
integrationTestCompile gebDependencies
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-jdbc'),
|
||||
"org.springframework.boot:spring-boot-starter-jdbc",
|
||||
|
||||
@@ -15,7 +15,6 @@ apply from: SAMPLE_GRADLE
|
||||
group = 'samples'
|
||||
ext {
|
||||
jsonassertVersion="1.3.0"
|
||||
assertjVersion = "2.4.0"
|
||||
}
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
@@ -14,6 +14,8 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session'),
|
||||
"org.springframework.boot:spring-boot-starter-data-mongodb",
|
||||
|
||||
@@ -15,6 +15,8 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
|
||||
@@ -23,7 +23,6 @@ include 'samples:security'
|
||||
include 'samples:users'
|
||||
include 'samples:websocket'
|
||||
include 'samples:mongo'
|
||||
include 'samples:grails3'
|
||||
|
||||
include 'spring-session'
|
||||
include 'spring-session-data-gemfire'
|
||||
|
||||
@@ -29,14 +29,14 @@ dependencies {
|
||||
"org.springframework.security:spring-security-web:$springSecurityVersion"
|
||||
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
integrationTestCompile "redis.clients:jedis:$jedisVersion",
|
||||
"org.apache.commons:commons-pool2:2.2",
|
||||
"org.apache.commons:commons-pool2:$commonsPoolVersion",
|
||||
"com.hazelcast:hazelcast-client:$hazelcastVersion",
|
||||
"com.h2database:h2:$h2Version",
|
||||
"org.hsqldb:hsqldb:2.3.3",
|
||||
"org.apache.derby:derby:10.12.1.1",
|
||||
"de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.50.2"
|
||||
"de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.50.5"
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
|
||||
testCompile "junit:junit:$junitVersion",
|
||||
"org.mockito:mockito-core:$mockitoVersion",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,9 +18,17 @@ package org.springframework.session.hazelcast;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.instance.HazelcastInstanceProxy;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.hazelcast.HazelcastSessionRepository.HazelcastSession;
|
||||
|
||||
@@ -34,8 +42,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
public abstract class AbstractHazelcastRepositoryITests {
|
||||
|
||||
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
|
||||
|
||||
@Autowired
|
||||
private HazelcastInstance hazelcast;
|
||||
private HazelcastInstance hazelcastInstance;
|
||||
|
||||
@Autowired
|
||||
private HazelcastSessionRepository repository;
|
||||
@@ -45,8 +55,8 @@ public abstract class AbstractHazelcastRepositoryITests {
|
||||
HazelcastSession sessionToSave = this.repository.createSession();
|
||||
String sessionId = sessionToSave.getId();
|
||||
|
||||
IMap<String, MapSession> hazelcastMap = this.hazelcast.getMap(
|
||||
"spring:session:sessions");
|
||||
IMap<String, MapSession> hazelcastMap = this.hazelcastInstance
|
||||
.getMap("spring:session:sessions");
|
||||
|
||||
assertThat(hazelcastMap.size()).isEqualTo(0);
|
||||
|
||||
@@ -60,4 +70,70 @@ public abstract class AbstractHazelcastRepositoryITests {
|
||||
assertThat(hazelcastMap.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test // gh-1076
|
||||
public void attemptToUpdateSessionAfterDelete() {
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
String sessionId = session.getId();
|
||||
this.repository.save(session);
|
||||
session = this.repository.getSession(sessionId);
|
||||
session.setAttribute("attributeName", "attributeValue");
|
||||
this.repository.delete(sessionId);
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(sessionId)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAndUpdateSession() {
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
String sessionId = session.getId();
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
session = this.repository.getSession(sessionId);
|
||||
session.setAttribute("attributeName", "attributeValue");
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(sessionId)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionWithSecurityContextAndFindById() {
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
String sessionId = session.getId();
|
||||
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(
|
||||
"saves-" + System.currentTimeMillis(), "password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(authentication);
|
||||
session.setAttribute(SPRING_SECURITY_CONTEXT, securityContext);
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(sessionId)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionWithSecurityContextAndFindByPrincipal() {
|
||||
Assume.assumeTrue("Hazelcast runs in embedded server topology",
|
||||
this.hazelcastInstance instanceof HazelcastInstanceProxy);
|
||||
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
|
||||
String username = "saves-" + System.currentTimeMillis();
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(username,
|
||||
"password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(authentication);
|
||||
session.setAttribute(SPRING_SECURITY_CONTEXT, securityContext);
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -49,12 +49,12 @@ public class HazelcastClientRepositoryITests extends AbstractHazelcastRepository
|
||||
private static HazelcastInstance hazelcastInstance;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
public static void setUpClass() {
|
||||
hazelcastInstance = HazelcastITestUtils.embeddedHazelcastServer(PORT);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void teardown() {
|
||||
public static void tearDownClass() {
|
||||
if (hazelcastInstance != null) {
|
||||
hazelcastInstance.shutdown();
|
||||
}
|
||||
@@ -65,7 +65,7 @@ public class HazelcastClientRepositoryITests extends AbstractHazelcastRepository
|
||||
static class HazelcastSessionConfig {
|
||||
|
||||
@Bean
|
||||
public HazelcastInstance embeddedHazelcastClient() {
|
||||
public HazelcastInstance hazelcastInstance() {
|
||||
ClientConfig clientConfig = new ClientConfig();
|
||||
clientConfig.getNetworkConfig().addAddress("127.0.0.1:" + PORT);
|
||||
return HazelcastClient.newHazelcastClient(clientConfig);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.session.hazelcast;
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.config.MapAttributeConfig;
|
||||
import com.hazelcast.config.MapIndexConfig;
|
||||
import com.hazelcast.config.NetworkConfig;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
@@ -46,8 +47,12 @@ public final class HazelcastITestUtils {
|
||||
|
||||
Config config = new Config();
|
||||
|
||||
config.getNetworkConfig()
|
||||
.setPort(port);
|
||||
NetworkConfig networkConfig = config.getNetworkConfig();
|
||||
|
||||
networkConfig.setPort(port);
|
||||
|
||||
networkConfig.getJoin()
|
||||
.getMulticastConfig().setEnabled(false);
|
||||
|
||||
config.getMapConfig("spring:session:sessions")
|
||||
.addMapAttributeConfig(attributeConfig)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -43,7 +43,7 @@ public class HazelcastServerRepositoryITests extends AbstractHazelcastRepository
|
||||
static class HazelcastSessionConfig {
|
||||
|
||||
@Bean
|
||||
public HazelcastInstance embeddedHazelcastServer() {
|
||||
public HazelcastInstance hazelcastInstance() {
|
||||
return HazelcastITestUtils.embeddedHazelcastServer();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -34,10 +34,8 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@@ -82,6 +80,19 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveWhenNoAttributesThenCanBeFound() {
|
||||
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
|
||||
.createSession();
|
||||
|
||||
this.repository.save(toSave);
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.getSession(toSave.getId());
|
||||
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saves() throws InterruptedException {
|
||||
String username = "saves-" + System.currentTimeMillis();
|
||||
@@ -100,9 +111,11 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
this.repository.save(toSave);
|
||||
|
||||
Session session = this.repository.getSession(toSave.getId());
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.getSession(toSave.getId());
|
||||
|
||||
assertThat(session.getId()).isEqualTo(toSave.getId());
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames());
|
||||
assertThat(session.getAttribute(expectedAttributeName))
|
||||
.isEqualTo(toSave.getAttribute(expectedAttributeName));
|
||||
@@ -135,7 +148,9 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
this.repository.save(toSave);
|
||||
toSave = this.repository.getSession(toSave.getId());
|
||||
|
||||
Session session = this.repository.getSession(toSave.getId());
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.getSession(toSave.getId());
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
assertThat(session.getAttributeNames().size()).isEqualTo(2);
|
||||
assertThat(session.getAttribute("a")).isEqualTo("b");
|
||||
assertThat(session.getAttribute("1")).isEqualTo("2");
|
||||
@@ -156,9 +171,11 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
toSave.setLastAccessedTime(lastAccessedTime);
|
||||
this.repository.save(toSave);
|
||||
|
||||
ExpiringSession session = this.repository.getSession(toSave.getId());
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.getSession(toSave.getId());
|
||||
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
assertThat(session.isExpired()).isFalse();
|
||||
assertThat(session.getLastAccessedTime()).isEqualTo(lastAccessedTime);
|
||||
}
|
||||
@@ -225,6 +242,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -247,6 +268,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -289,6 +314,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -336,6 +365,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -395,6 +428,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -416,6 +453,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -455,6 +496,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -499,6 +544,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -559,6 +608,46 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
assertThat(this.repository.getSession(session.getId())).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-1031
|
||||
public void saveDeleted() {
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
|
||||
this.repository.save(session);
|
||||
session = this.repository.getSession(session.getId());
|
||||
this.repository.delete(session.getId());
|
||||
session.setLastAccessedTime(System.currentTimeMillis());
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(session.getId())).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-1031
|
||||
public void saveDeletedAddAttribute() {
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
|
||||
this.repository.save(session);
|
||||
session = this.repository.getSession(session.getId());
|
||||
this.repository.delete(session.getId());
|
||||
session.setLastAccessedTime(System.currentTimeMillis());
|
||||
session.setAttribute("testName", "testValue1");
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(session.getId())).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-1203
|
||||
public void saveWithLargeAttribute() {
|
||||
String attributeName = "largeAttribute";
|
||||
int arraySize = 4000;
|
||||
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository
|
||||
.createSession();
|
||||
session.setAttribute(attributeName, new byte[arraySize]);
|
||||
this.repository.save(session);
|
||||
session = this.repository.getSession(session.getId());
|
||||
|
||||
assertThat(session).isNotNull();
|
||||
assertThat((byte[]) session.getAttribute(attributeName)).hasSize(arraySize);
|
||||
}
|
||||
|
||||
private String getSecurityName() {
|
||||
return this.context.getAuthentication().getName();
|
||||
}
|
||||
|
||||
@@ -14,16 +14,7 @@
|
||||
<ports>0</ports>
|
||||
</outbound-ports>
|
||||
<join>
|
||||
<multicast enabled="false">
|
||||
</multicast>
|
||||
<tcp-ip enabled="true">
|
||||
<interface>127.0.0.1</interface>
|
||||
<member-list>
|
||||
<member>127.0.0.1</member>
|
||||
</member-list>
|
||||
</tcp-ip>
|
||||
<aws enabled="false">
|
||||
</aws>
|
||||
<multicast enabled="false"/>
|
||||
</join>
|
||||
</network>
|
||||
|
||||
@@ -14,16 +14,7 @@
|
||||
<ports>0</ports>
|
||||
</outbound-ports>
|
||||
<join>
|
||||
<multicast enabled="false">
|
||||
</multicast>
|
||||
<tcp-ip enabled="true">
|
||||
<interface>127.0.0.1</interface>
|
||||
<member-list>
|
||||
<member>127.0.0.1</member>
|
||||
</member-list>
|
||||
</tcp-ip>
|
||||
<aws enabled="false">
|
||||
</aws>
|
||||
<multicast enabled="false"/>
|
||||
</join>
|
||||
</network>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -141,7 +142,7 @@ public final class MapSession implements ExpiringSession, Serializable {
|
||||
}
|
||||
|
||||
public Set<String> getAttributeNames() {
|
||||
return this.sessionAttrs.keySet();
|
||||
return new HashSet<String>(this.sessionAttrs.keySet());
|
||||
}
|
||||
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
|
||||
@@ -201,7 +201,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* <p>
|
||||
* One problem with relying on Redis expiration exclusively is that Redis makes no
|
||||
* guarantee of when the expired event will be fired if they key has not been accessed.
|
||||
* guarantee of when the expired event will be fired if the key has not been accessed.
|
||||
* Specifically the background task that Redis uses to clean up expired keys is a low
|
||||
* priority task and may not trigger the key expiration. For additional details see
|
||||
* <a href="http://redis.io/topics/notifications">Timing of expired events</a> section in
|
||||
@@ -212,7 +212,7 @@ import org.springframework.util.Assert;
|
||||
* To circumvent the fact that expired events are not guaranteed to happen we can ensure
|
||||
* that each key is accessed when it is expected to expire. This means that if the TTL is
|
||||
* expired on the key, Redis will remove the key and fire the expired event when we try to
|
||||
* access they key.
|
||||
* access the key.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
@@ -521,6 +521,7 @@ public class RedisOperationsSessionRepository implements
|
||||
if (session == null) {
|
||||
logger.warn("Unable to publish SessionDestroyedEvent for session "
|
||||
+ sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -535,8 +536,6 @@ public class RedisOperationsSessionRepository implements
|
||||
else {
|
||||
handleExpired(session);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ import javax.annotation.PreDestroy;
|
||||
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.map.AbstractEntryProcessor;
|
||||
import com.hazelcast.map.EntryProcessor;
|
||||
import com.hazelcast.map.listener.EntryAddedListener;
|
||||
import com.hazelcast.map.listener.EntryEvictedListener;
|
||||
import com.hazelcast.map.listener.EntryRemovedListener;
|
||||
@@ -205,12 +203,20 @@ public class HazelcastSessionRepository implements
|
||||
this.sessions.set(session.getId(), session.getDelegate(),
|
||||
session.getMaxInactiveIntervalInSeconds(), TimeUnit.SECONDS);
|
||||
}
|
||||
else if (session.changed) {
|
||||
this.sessions.executeOnKey(session.getId(),
|
||||
new SessionUpdateEntryProcessor(session.getLastAccessedTime(),
|
||||
session.getMaxInactiveIntervalInSeconds(), session.delta));
|
||||
else if (session.hasChanges()) {
|
||||
SessionUpdateEntryProcessor entryProcessor = new SessionUpdateEntryProcessor();
|
||||
if (session.lastAccessedTimeChanged) {
|
||||
entryProcessor.setLastAccessedTime(session.getLastAccessedTime());
|
||||
}
|
||||
if (session.maxInactiveIntervalChanged) {
|
||||
entryProcessor.setMaxInactiveInterval(session.getMaxInactiveIntervalInSeconds());
|
||||
}
|
||||
if (!session.delta.isEmpty()) {
|
||||
entryProcessor.setDelta(session.delta);
|
||||
}
|
||||
this.sessions.executeOnKey(session.getId(), entryProcessor);
|
||||
}
|
||||
session.clearFlags();
|
||||
session.clearChangeFlags();
|
||||
}
|
||||
|
||||
public HazelcastSession getSession(String id) {
|
||||
@@ -279,7 +285,11 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
private boolean isNew;
|
||||
|
||||
private boolean changed;
|
||||
private boolean sessionIdChanged;
|
||||
|
||||
private boolean lastAccessedTimeChanged;
|
||||
|
||||
private boolean maxInactiveIntervalChanged;
|
||||
|
||||
private Map<String, Object> delta = new HashMap<String, Object>();
|
||||
|
||||
@@ -305,7 +315,7 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
public void setLastAccessedTime(long lastAccessedTime) {
|
||||
this.delegate.setLastAccessedTime(lastAccessedTime);
|
||||
this.changed = true;
|
||||
this.lastAccessedTimeChanged = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
@@ -327,7 +337,7 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
this.delegate.setMaxInactiveIntervalInSeconds(interval);
|
||||
this.changed = true;
|
||||
this.maxInactiveIntervalChanged = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
@@ -346,14 +356,12 @@ public class HazelcastSessionRepository implements
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
this.delegate.setAttribute(attributeName, attributeValue);
|
||||
this.delta.put(attributeName, attributeValue);
|
||||
this.changed = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
public void removeAttribute(String attributeName) {
|
||||
this.delegate.removeAttribute(attributeName);
|
||||
this.delta.put(attributeName, null);
|
||||
this.changed = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
@@ -361,9 +369,16 @@ public class HazelcastSessionRepository implements
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
void clearFlags() {
|
||||
boolean hasChanges() {
|
||||
return (this.lastAccessedTimeChanged || this.maxInactiveIntervalChanged
|
||||
|| !this.delta.isEmpty());
|
||||
}
|
||||
|
||||
void clearChangeFlags() {
|
||||
this.isNew = false;
|
||||
this.changed = false;
|
||||
this.lastAccessedTimeChanged = false;
|
||||
this.sessionIdChanged = false;
|
||||
this.maxInactiveIntervalChanged = false;
|
||||
this.delta.clear();
|
||||
}
|
||||
|
||||
@@ -375,44 +390,4 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hazelcast {@link EntryProcessor} responsible for handling updates to session.
|
||||
*
|
||||
* @since 1.3.2
|
||||
* @see #save(HazelcastSession)
|
||||
*/
|
||||
private static final class SessionUpdateEntryProcessor
|
||||
extends AbstractEntryProcessor<String, MapSession> {
|
||||
|
||||
private final long lastAccessedTime;
|
||||
|
||||
private final int maxInactiveIntervalInSeconds;
|
||||
|
||||
private final Map<String, Object> delta;
|
||||
|
||||
SessionUpdateEntryProcessor(long lastAccessedTime,
|
||||
int maxInactiveIntervalInSeconds, Map<String, Object> delta) {
|
||||
this.lastAccessedTime = lastAccessedTime;
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
this.delta = delta;
|
||||
}
|
||||
|
||||
public Object process(Map.Entry<String, MapSession> entry) {
|
||||
MapSession value = entry.getValue();
|
||||
value.setLastAccessedTime(this.lastAccessedTime);
|
||||
value.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds);
|
||||
for (final Map.Entry<String, Object> attribute : this.delta.entrySet()) {
|
||||
if (attribute.getValue() != null) {
|
||||
value.setAttribute(attribute.getKey(), attribute.getValue());
|
||||
}
|
||||
else {
|
||||
value.removeAttribute(attribute.getKey());
|
||||
}
|
||||
}
|
||||
entry.setValue(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2014-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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://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.hazelcast;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.hazelcast.map.AbstractEntryProcessor;
|
||||
import com.hazelcast.map.EntryProcessor;
|
||||
|
||||
import org.springframework.session.MapSession;
|
||||
|
||||
/**
|
||||
* Hazelcast {@link EntryProcessor} responsible for handling updates to session.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @since 1.3.4
|
||||
* @see HazelcastSessionRepository#save(HazelcastSessionRepository.HazelcastSession)
|
||||
*/
|
||||
public class SessionUpdateEntryProcessor
|
||||
extends AbstractEntryProcessor<String, MapSession> {
|
||||
|
||||
private long lastAccessedTime;
|
||||
|
||||
private boolean lastAccessedTimeSet;
|
||||
|
||||
private int maxInactiveInterval;
|
||||
|
||||
private boolean maxInactiveIntervalSet;
|
||||
|
||||
private Map<String, Object> delta;
|
||||
|
||||
public Object process(Map.Entry<String, MapSession> entry) {
|
||||
MapSession value = entry.getValue();
|
||||
if (value == null) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
if (this.lastAccessedTimeSet) {
|
||||
value.setLastAccessedTime(this.lastAccessedTime);
|
||||
}
|
||||
if (this.maxInactiveIntervalSet) {
|
||||
value.setMaxInactiveIntervalInSeconds(this.maxInactiveInterval);
|
||||
}
|
||||
if (this.delta != null) {
|
||||
for (final Map.Entry<String, Object> attribute : this.delta.entrySet()) {
|
||||
if (attribute.getValue() != null) {
|
||||
value.setAttribute(attribute.getKey(), attribute.getValue());
|
||||
}
|
||||
else {
|
||||
value.removeAttribute(attribute.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
entry.setValue(value);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
void setLastAccessedTime(long lastAccessedTime) {
|
||||
this.lastAccessedTime = lastAccessedTime;
|
||||
this.lastAccessedTimeSet = true;
|
||||
}
|
||||
|
||||
void setMaxInactiveInterval(int maxInactiveInterval) {
|
||||
this.maxInactiveInterval = maxInactiveInterval;
|
||||
this.maxInactiveIntervalSet = true;
|
||||
}
|
||||
|
||||
void setDelta(Map<String, Object> delta) {
|
||||
this.delta = delta;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -143,7 +143,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
private static final String CREATE_SESSION_ATTRIBUTE_QUERY =
|
||||
"INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " +
|
||||
"VALUES (?, ?, ?)";
|
||||
"SELECT SESSION_ID, ?, ? " +
|
||||
"FROM %TABLE_NAME% " +
|
||||
"WHERE SESSION_ID = ?";
|
||||
|
||||
private static final String GET_SESSION_QUERY =
|
||||
"SELECT S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " +
|
||||
@@ -188,8 +190,7 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
private final TransactionOperations transactionOperations;
|
||||
|
||||
private final ResultSetExtractor<List<ExpiringSession>> extractor =
|
||||
new ExpiringSessionResultSetExtractor();
|
||||
private final ResultSetExtractor<List<JdbcSession>> extractor = new SessionResultSetExtractor();
|
||||
|
||||
/**
|
||||
* The name of database table used by Spring Session to store sessions.
|
||||
@@ -399,9 +400,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
String attributeName = attributeNames.get(i);
|
||||
ps.setString(1, session.getId());
|
||||
ps.setString(2, attributeName);
|
||||
serialize(ps, 3, session.getAttribute(attributeName));
|
||||
ps.setString(1, attributeName);
|
||||
serialize(ps, 2, session.getAttribute(attributeName));
|
||||
ps.setString(3, session.getId());
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
@@ -466,9 +467,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
new PreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setString(1, session.getId());
|
||||
ps.setString(2, entry.getKey());
|
||||
serialize(ps, 3, entry.getValue());
|
||||
ps.setString(1, entry.getKey());
|
||||
serialize(ps, 2, entry.getValue());
|
||||
ps.setString(3, session.getId());
|
||||
}
|
||||
|
||||
});
|
||||
@@ -484,10 +485,10 @@ public class JdbcOperationsSessionRepository implements
|
||||
}
|
||||
|
||||
public JdbcSession getSession(final String id) {
|
||||
final ExpiringSession session = this.transactionOperations.execute(new TransactionCallback<ExpiringSession>() {
|
||||
final JdbcSession session = this.transactionOperations.execute(new TransactionCallback<JdbcSession>() {
|
||||
|
||||
public ExpiringSession doInTransaction(TransactionStatus status) {
|
||||
List<ExpiringSession> sessions = JdbcOperationsSessionRepository.this.jdbcOperations.query(
|
||||
public JdbcSession doInTransaction(TransactionStatus status) {
|
||||
List<JdbcSession> sessions = JdbcOperationsSessionRepository.this.jdbcOperations.query(
|
||||
JdbcOperationsSessionRepository.this.getSessionQuery,
|
||||
new PreparedStatementSetter() {
|
||||
|
||||
@@ -511,7 +512,7 @@ public class JdbcOperationsSessionRepository implements
|
||||
delete(id);
|
||||
}
|
||||
else {
|
||||
return new JdbcSession(session);
|
||||
return session;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -534,9 +535,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<ExpiringSession> sessions = this.transactionOperations.execute(new TransactionCallback<List<ExpiringSession>>() {
|
||||
List<JdbcSession> sessions = this.transactionOperations.execute(new TransactionCallback<List<JdbcSession>>() {
|
||||
|
||||
public List<ExpiringSession> doInTransaction(TransactionStatus status) {
|
||||
public List<JdbcSession> doInTransaction(TransactionStatus status) {
|
||||
return JdbcOperationsSessionRepository.this.jdbcOperations.query(
|
||||
JdbcOperationsSessionRepository.this.listSessionsByPrincipalNameQuery,
|
||||
new PreparedStatementSetter() {
|
||||
@@ -555,8 +556,8 @@ public class JdbcOperationsSessionRepository implements
|
||||
Map<String, JdbcSession> sessionMap = new HashMap<String, JdbcSession>(
|
||||
sessions.size());
|
||||
|
||||
for (ExpiringSession session : sessions) {
|
||||
sessionMap.put(session.getId(), new JdbcSession(session));
|
||||
for (JdbcSession session : sessions) {
|
||||
sessionMap.put(session.getId(), session);
|
||||
}
|
||||
|
||||
return sessionMap;
|
||||
@@ -764,33 +765,33 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
}
|
||||
|
||||
private class ExpiringSessionResultSetExtractor
|
||||
implements ResultSetExtractor<List<ExpiringSession>> {
|
||||
private class SessionResultSetExtractor implements ResultSetExtractor<List<JdbcSession>> {
|
||||
|
||||
public List<ExpiringSession> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
List<ExpiringSession> sessions = new ArrayList<ExpiringSession>();
|
||||
public List<JdbcSession> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
List<JdbcSession> sessions = new ArrayList<JdbcSession>();
|
||||
while (rs.next()) {
|
||||
String id = rs.getString("SESSION_ID");
|
||||
MapSession session;
|
||||
JdbcSession session;
|
||||
if (sessions.size() > 0 && getLast(sessions).getId().equals(id)) {
|
||||
session = (MapSession) getLast(sessions);
|
||||
session = getLast(sessions);
|
||||
}
|
||||
else {
|
||||
session = new MapSession(id);
|
||||
session.setCreationTime(rs.getLong("CREATION_TIME"));
|
||||
session.setLastAccessedTime(rs.getLong("LAST_ACCESS_TIME"));
|
||||
session.setMaxInactiveIntervalInSeconds(rs.getInt("MAX_INACTIVE_INTERVAL"));
|
||||
MapSession delegate = new MapSession(id);
|
||||
delegate.setCreationTime(rs.getLong("CREATION_TIME"));
|
||||
delegate.setLastAccessedTime(rs.getLong("LAST_ACCESS_TIME"));
|
||||
delegate.setMaxInactiveIntervalInSeconds(rs.getInt("MAX_INACTIVE_INTERVAL"));
|
||||
session = new JdbcSession(delegate);
|
||||
}
|
||||
String attributeName = rs.getString("ATTRIBUTE_NAME");
|
||||
if (attributeName != null) {
|
||||
session.setAttribute(attributeName, deserialize(rs, "ATTRIBUTE_BYTES"));
|
||||
session.delegate.setAttribute(attributeName, deserialize(rs, "ATTRIBUTE_BYTES"));
|
||||
}
|
||||
sessions.add(session);
|
||||
}
|
||||
return sessions;
|
||||
}
|
||||
|
||||
private ExpiringSession getLast(List<ExpiringSession> sessions) {
|
||||
private JdbcSession getLast(List<JdbcSession> sessions) {
|
||||
return sessions.get(sessions.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -33,8 +33,10 @@ import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.core.serializer.support.DeserializingConverter;
|
||||
import org.springframework.core.serializer.support.SerializingConverter;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
|
||||
@@ -85,7 +87,7 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
|
||||
@Bean
|
||||
public JdbcOperationsSessionRepository sessionRepository(
|
||||
@Qualifier("springSessionJdbcOperations") JdbcOperations jdbcOperations,
|
||||
@Qualifier("springSessionJdbcOperations") JdbcTemplate jdbcOperations,
|
||||
PlatformTransactionManager transactionManager) {
|
||||
JdbcOperationsSessionRepository sessionRepository =
|
||||
new JdbcOperationsSessionRepository(jdbcOperations, transactionManager);
|
||||
@@ -98,6 +100,11 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
if (this.lobHandler != null) {
|
||||
sessionRepository.setLobHandler(this.lobHandler);
|
||||
}
|
||||
else if (requiresTemporaryLob(jdbcOperations.getDataSource())) {
|
||||
DefaultLobHandler lobHandler = new DefaultLobHandler();
|
||||
lobHandler.setCreateTemporaryLob(true);
|
||||
sessionRepository.setLobHandler(lobHandler);
|
||||
}
|
||||
if (this.springSessionConversionService != null) {
|
||||
sessionRepository.setConversionService(this.springSessionConversionService);
|
||||
}
|
||||
@@ -111,11 +118,22 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
return sessionRepository;
|
||||
}
|
||||
|
||||
private static boolean requiresTemporaryLob(DataSource dataSource) {
|
||||
try {
|
||||
String productName = (String) JdbcUtils.extractDatabaseMetaData(dataSource,
|
||||
"getDatabaseProductName");
|
||||
return "Oracle".equalsIgnoreCase(JdbcUtils.commonDatabaseName(productName));
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be a separate method because some ClassLoaders load the entire method
|
||||
* definition even if an if statement guards against it loading. This means that older
|
||||
* versions of Spring would cause a NoSuchMethodError if this were defined in
|
||||
* {@link #sessionRepository(JdbcOperations, PlatformTransactionManager)}.
|
||||
* {@link #sessionRepository(JdbcTemplate, PlatformTransactionManager)}.
|
||||
*
|
||||
* @return the default {@link ConversionService}
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,9 @@ 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;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link CookieSerializer}.
|
||||
*
|
||||
@@ -35,6 +38,8 @@ import javax.servlet.http.HttpServletResponse;
|
||||
*/
|
||||
public class DefaultCookieSerializer implements CookieSerializer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DefaultCookieSerializer.class);
|
||||
|
||||
private String cookieName = "SESSION";
|
||||
|
||||
private Boolean useSecureCookie;
|
||||
@@ -138,6 +143,7 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
return new String(decodedCookieBytes);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.debug("Unable to Base64 decode value: " + base64Value);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,11 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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;
|
||||
@@ -48,7 +51,7 @@ import org.springframework.session.SessionRepository;
|
||||
* {@link org.springframework.session.SessionRepository}.
|
||||
*
|
||||
* The {@link SessionRepositoryFilter} uses a {@link HttpSessionStrategy} (default
|
||||
* {@link CookieHttpSessionStrategy} to bridge logic between an
|
||||
* {@link CookieHttpSessionStrategy}) to bridge logic between an
|
||||
* {@link javax.servlet.http.HttpSession} and the
|
||||
* {@link org.springframework.session.Session} abstraction. Specifically:
|
||||
*
|
||||
@@ -72,6 +75,7 @@ import org.springframework.session.SessionRepository;
|
||||
* @param <S> the {@link ExpiringSession} type.
|
||||
* @since 1.0
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*/
|
||||
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
|
||||
public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
@@ -397,6 +401,12 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
.getRequestedSessionId(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestDispatcher getRequestDispatcher(String path) {
|
||||
RequestDispatcher requestDispatcher = super.getRequestDispatcher(path);
|
||||
return new SessionCommittingRequestDispatcher(requestDispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows creating an HttpSession from a Session instance.
|
||||
*
|
||||
@@ -417,6 +427,34 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
SessionRepositoryFilter.this.sessionRepository.delete(getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures session is committed before issuing an include.
|
||||
*
|
||||
* @since 1.3.4
|
||||
*/
|
||||
private final class SessionCommittingRequestDispatcher
|
||||
implements RequestDispatcher {
|
||||
|
||||
private final RequestDispatcher delegate;
|
||||
|
||||
SessionCommittingRequestDispatcher(RequestDispatcher delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public void forward(ServletRequest request, ServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
this.delegate.forward(request, response);
|
||||
}
|
||||
|
||||
public void include(ServletRequest request, ServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
SessionRepositoryRequestWrapper.this.commitSession();
|
||||
this.delegate.include(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -64,4 +64,18 @@ public class MapSessionRepositoryTests {
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds())
|
||||
.isEqualTo(expectedMaxInterval);
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
ExpiringSession session = this.repository.createSession();
|
||||
session.setAttribute("attribute1", "value1");
|
||||
session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : session.getAttributeNames()) {
|
||||
session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -85,6 +85,18 @@ public class MapSessionTests {
|
||||
assertThat(this.session.isExpired(now)).isTrue();
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
this.session.setAttribute("attribute1", "value1");
|
||||
this.session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : this.session.getAttributeNames()) {
|
||||
this.session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(this.session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
static class CustomSession implements ExpiringSession {
|
||||
|
||||
public long getCreationTime() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -59,6 +59,7 @@ import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
@@ -529,6 +530,104 @@ public class RedisOperationsSessionRepositoryTests {
|
||||
verify(this.defaultSerializer).deserialize(body);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageDeletedSessionFound() throws Exception {
|
||||
String deletedId = "deleted-id";
|
||||
given(this.redisOperations.boundHashOps(getKey(deletedId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 0,
|
||||
RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
|
||||
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
|
||||
String channel = "__keyevent@0__:del";
|
||||
String body = "spring:session:sessions:expires:" + deletedId;
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
|
||||
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
|
||||
|
||||
verify(this.redisOperations).boundHashOps(eq(getKey(deletedId)));
|
||||
verify(this.boundHashOperations).entries();
|
||||
verify(this.publisher).publishEvent(this.event.capture());
|
||||
assertThat(this.event.getValue().getSessionId()).isEqualTo(deletedId);
|
||||
verifyZeroInteractions(this.defaultSerializer);
|
||||
verifyZeroInteractions(this.publisher);
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.boundHashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageDeletedSessionNotFound() throws Exception {
|
||||
String deletedId = "deleted-id";
|
||||
given(this.redisOperations.boundHashOps(getKey(deletedId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
given(this.boundHashOperations.entries()).willReturn(map());
|
||||
|
||||
String channel = "__keyevent@0__:del";
|
||||
String body = "spring:session:sessions:expires:" + deletedId;
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
|
||||
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
|
||||
|
||||
verify(this.redisOperations).boundHashOps(eq(getKey(deletedId)));
|
||||
verify(this.boundHashOperations).entries();
|
||||
verifyZeroInteractions(this.defaultSerializer);
|
||||
verifyZeroInteractions(this.publisher);
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.boundHashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageExpiredSessionFound() throws Exception {
|
||||
String expiredId = "expired-id";
|
||||
given(this.redisOperations.boundHashOps(getKey(expiredId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 1,
|
||||
RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
|
||||
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
|
||||
String channel = "__keyevent@0__:expired";
|
||||
String body = "spring:session:sessions:expires:" + expiredId;
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
|
||||
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
|
||||
|
||||
verify(this.redisOperations).boundHashOps(eq(getKey(expiredId)));
|
||||
verify(this.boundHashOperations).entries();
|
||||
verify(this.publisher).publishEvent(this.event.capture());
|
||||
assertThat(this.event.getValue().getSessionId()).isEqualTo(expiredId);
|
||||
verifyZeroInteractions(this.defaultSerializer);
|
||||
verifyZeroInteractions(this.publisher);
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.boundHashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageExpiredSessionNotFound() throws Exception {
|
||||
String expiredId = "expired-id";
|
||||
given(this.redisOperations.boundHashOps(getKey(expiredId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
given(this.boundHashOperations.entries()).willReturn(map());
|
||||
|
||||
String channel = "__keyevent@0__:expired";
|
||||
String body = "spring:session:sessions:expires:" + expiredId;
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
|
||||
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
|
||||
|
||||
verify(this.redisOperations).boundHashOps(eq(getKey(expiredId)));
|
||||
verify(this.boundHashOperations).entries();
|
||||
verifyZeroInteractions(this.defaultSerializer);
|
||||
verifyZeroInteractions(this.publisher);
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.boundHashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePrincipalIndex() {
|
||||
PrincipalNameResolver resolver = RedisOperationsSessionRepository.PRINCIPAL_NAME_RESOLVER;
|
||||
@@ -706,6 +805,19 @@ public class RedisOperationsSessionRepositoryTests {
|
||||
this.redisRepository.setRedisFlushMode(null);
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
RedisSession session = this.redisRepository.new RedisSession(this.cached);
|
||||
session.setAttribute("attribute1", "value1");
|
||||
session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : session.getAttributeNames()) {
|
||||
session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
private String getKey(String id) {
|
||||
return "spring:session:sessions:" + id;
|
||||
}
|
||||
|
||||
@@ -339,4 +339,17 @@ public class HazelcastSessionRepositoryTests {
|
||||
verify(this.sessions, times(1)).values(isA(EqualPredicate.class));
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
session.setAttribute("attribute1", "value1");
|
||||
session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : session.getAttributeNames()) {
|
||||
session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -412,7 +412,7 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
public void getSessionExpired() {
|
||||
MapSession expired = new MapSession();
|
||||
JdbcOperationsSessionRepository.JdbcSession expired = this.repository.new JdbcSession();
|
||||
expired.setLastAccessedTime(System.currentTimeMillis() -
|
||||
(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000));
|
||||
given(this.jdbcOperations.query(isA(String.class),
|
||||
@@ -432,7 +432,8 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
public void getSessionFound() {
|
||||
MapSession saved = new MapSession();
|
||||
JdbcOperationsSessionRepository.JdbcSession saved = this.repository.new JdbcSession(
|
||||
new MapSession());
|
||||
saved.setAttribute("savedName", "savedValue");
|
||||
given(this.jdbcOperations.query(isA(String.class),
|
||||
isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class)))
|
||||
@@ -493,11 +494,12 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
String principal = "username";
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(principal,
|
||||
"notused", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
List<MapSession> saved = new ArrayList<MapSession>(2);
|
||||
MapSession saved1 = new MapSession();
|
||||
List<JdbcOperationsSessionRepository.JdbcSession> saved =
|
||||
new ArrayList<JdbcOperationsSessionRepository.JdbcSession>(2);
|
||||
JdbcOperationsSessionRepository.JdbcSession saved1 = this.repository.new JdbcSession();
|
||||
saved1.setAttribute(SPRING_SECURITY_CONTEXT, authentication);
|
||||
saved.add(saved1);
|
||||
MapSession saved2 = new MapSession();
|
||||
JdbcOperationsSessionRepository.JdbcSession saved2 = this.repository.new JdbcSession();
|
||||
saved2.setAttribute(SPRING_SECURITY_CONTEXT, authentication);
|
||||
saved.add(saved2);
|
||||
given(this.jdbcOperations.query(isA(String.class),
|
||||
@@ -523,6 +525,19 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
verify(this.jdbcOperations, times(1)).update(startsWith("DELETE"), anyLong());
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
|
||||
session.setAttribute("attribute1", "value1");
|
||||
session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : session.getAttributeNames()) {
|
||||
session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
private void assertPropagationRequiresNew() {
|
||||
ArgumentCaptor<TransactionDefinition> argument =
|
||||
ArgumentCaptor.forClass(TransactionDefinition.class);
|
||||
|
||||
@@ -1175,6 +1175,22 @@ public class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test // gh-1243
|
||||
public void doFilterInclude() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest,
|
||||
HttpServletResponse wrappedResponse)
|
||||
throws IOException, ServletException {
|
||||
String id = wrappedRequest.getSession().getId();
|
||||
wrappedRequest.getRequestDispatcher("/").include(wrappedRequest,
|
||||
wrappedResponse);
|
||||
assertThat(SessionRepositoryFilterTests.this.sessionRepository
|
||||
.getSession(id)).isNotNull();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- MultiHttpSessionStrategyAdapter
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user