Compare commits

...

12 Commits

Author SHA1 Message Date
Rob Winch
60cd6d8be6 Release 2.1.4.RELEASE 2019-02-13 15:55:29 -06:00
Rob Winch
5503057523 Update to Spring Security 5.1.4
Fixes: gh-1329
2019-02-13 15:54:46 -06:00
Vedran Pavic
8fc2f1130a Update integration tests 2019-02-13 19:36:48 +01:00
Vedran Pavic
f5d63efcf1 Upgrade test dependencies 2019-02-13 19:32:40 +01:00
Vedran Pavic
ed76514f30 Upgrade spring-build-conventions to 0.0.23.RELEASE 2019-02-13 19:26:19 +01:00
Vedran Pavic
e1c0d62d33 Upgrade Reactor to Californium-SR5
Resolves: #1326
2019-02-13 19:24:42 +01:00
Vedran Pavic
8041358d18 Upgrade Spring Data to Lovelace-SR5
Resolves: #1325
2019-02-13 19:24:09 +01:00
Vedran Pavic
cdd85cb349 Upgrade Spring Framework to 5.1.5.RELEASE
Resolves: #1324
2019-02-13 19:23:46 +01:00
Vedran Pavic
381a07cb8c Ignore failed rename operation for deleted session
In scenario with concurrent requests attempting to change session id, the "ERR no such key" error will occur for a thread that comes in second. This commit addresses the problem by ignoring the aforementioned error.

Resolves: #1270
2019-01-29 21:29:10 +01:00
Vedran Pavic
0e89539e20 Upgrade samples to Spring Boot 2.1.2.RELEASE
Resolves: #1318
2019-01-16 22:15:51 +01:00
Vedran Pavic
f00a1b9c6f Fix HazelcastSessionRepository to update TTL when maxInactiveInterval is changed
Resolves: #1300
2019-01-12 12:22:45 +01:00
Rob Winch
39cecb0902 Next Development Version 2019-01-10 21:36:58 -06:00
10 changed files with 100 additions and 34 deletions

View File

@@ -4,7 +4,7 @@ buildscript {
snapshotBuild = version.endsWith('SNAPSHOT')
milestoneBuild = !(releaseBuild || snapshotBuild)
springBootVersion = '2.1.1.RELEASE'
springBootVersion = '2.1.2.RELEASE'
}
repositories {
@@ -13,7 +13,7 @@ buildscript {
}
dependencies {
classpath 'io.spring.gradle:spring-build-conventions:0.0.22.RELEASE'
classpath 'io.spring.gradle:spring-build-conventions:0.0.23.RELEASE'
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
}
}

View File

@@ -1 +1 @@
version=2.1.3.RELEASE
version=2.1.4.RELEASE

View File

@@ -1,11 +1,11 @@
dependencyManagement {
imports {
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.6'
mavenBom 'io.projectreactor:reactor-bom:Californium-SR4'
mavenBom 'org.springframework:spring-framework-bom:5.1.4.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Lovelace-SR4'
mavenBom 'org.springframework.security:spring-security-bom:5.1.3.RELEASE'
mavenBom 'org.testcontainers:testcontainers-bom:1.10.5'
mavenBom 'io.projectreactor:reactor-bom:Californium-SR5'
mavenBom 'org.springframework:spring-framework-bom:5.1.5.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Lovelace-SR5'
mavenBom 'org.springframework.security:spring-security-bom:5.1.4.RELEASE'
mavenBom 'org.testcontainers:testcontainers-bom:1.10.6'
}
dependencies {
@@ -15,19 +15,19 @@ dependencyManagement {
}
dependency 'com.h2database:h2:1.4.197'
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.0.0.jre8'
dependency 'com.zaxxer:HikariCP:3.3.0'
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8'
dependency 'com.zaxxer:HikariCP:3.3.1'
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
dependency 'io.lettuce:lettuce-core:5.1.3.RELEASE'
dependency 'io.lettuce:lettuce-core:5.1.4.RELEASE'
dependency 'javax.annotation:javax.annotation-api:1.3.2'
dependency 'javax.servlet:javax.servlet-api:4.0.1'
dependency 'junit:junit:4.12'
dependency 'mysql:mysql-connector-java:8.0.13'
dependency 'mysql:mysql-connector-java:8.0.15'
dependency 'org.apache.derby:derby:10.14.2.0'
dependency 'org.assertj:assertj-core:3.11.1'
dependency 'org.hsqldb:hsqldb:2.4.1'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.3.0'
dependency 'org.mockito:mockito-core:2.23.4'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.4.0'
dependency 'org.mockito:mockito-core:2.24.0'
dependency 'org.postgresql:postgresql:42.2.5'
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 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.
@@ -600,6 +600,25 @@ public class RedisOperationsSessionRepositoryITests extends AbstractRedisITests
assertThat(this.repository.findById(sessionId)).isNull();
}
@Test // gh-1270
public void changeSessionIdSaveConcurrently() {
RedisSession toSave = this.repository.createSession();
String originalId = toSave.getId();
this.repository.save(toSave);
RedisSession copy1 = this.repository.findById(originalId);
RedisSession copy2 = this.repository.findById(originalId);
copy1.changeSessionId();
this.repository.save(copy1);
copy2.changeSessionId();
this.repository.save(copy2);
assertThat(this.repository.findById(originalId)).isNull();
assertThat(this.repository.findById(copy1.getId())).isNotNull();
assertThat(this.repository.findById(copy2.getId())).isNull();
}
private String getSecurityName() {
return this.context.getAuthentication().getName();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 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.
@@ -864,24 +864,34 @@ public class RedisOperationsSessionRepository implements
if (!isNew()) {
String originalSessionIdKey = getSessionKey(this.originalSessionId);
String sessionIdKey = getSessionKey(sessionId);
RedisOperationsSessionRepository.this.sessionRedisOperations.rename(
originalSessionIdKey, sessionIdKey);
try {
RedisOperationsSessionRepository.this.sessionRedisOperations
.rename(originalSessionIdKey, sessionIdKey);
}
catch (NonTransientDataAccessException ex) {
handleErrNoSuchKeyError(ex);
}
String originalExpiredKey = getExpiredKey(this.originalSessionId);
String expiredKey = getExpiredKey(sessionId);
try {
RedisOperationsSessionRepository.this.sessionRedisOperations.rename(
originalExpiredKey, expiredKey);
RedisOperationsSessionRepository.this.sessionRedisOperations
.rename(originalExpiredKey, expiredKey);
}
catch (NonTransientDataAccessException ex) {
if (!"ERR no such key".equals(NestedExceptionUtils
.getMostSpecificCause(ex).getMessage())) {
throw ex;
}
handleErrNoSuchKeyError(ex);
}
}
this.originalSessionId = sessionId;
}
}
private void handleErrNoSuchKeyError(NonTransientDataAccessException ex) {
if (!"ERR no such key"
.equals(NestedExceptionUtils.getMostSpecificCause(ex).getMessage())) {
throw ex;
}
}
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 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.
@@ -181,6 +181,28 @@ public class EnableHazelcastHttpSessionEventsTests<S extends Session> {
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isFalse();
}
@Test // gh-1300
public void updateMaxInactiveIntervalTest() throws InterruptedException {
S sessionToSave = this.repository.createSession();
sessionToSave.setMaxInactiveInterval(Duration.ofMinutes(30));
this.repository.save(sessionToSave);
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(this.registry.<SessionCreatedEvent>getEvent(sessionToSave.getId()))
.isInstanceOf(SessionCreatedEvent.class);
this.registry.clear();
S sessionToUpdate = this.repository.findById(sessionToSave.getId());
sessionToUpdate.setLastAccessedTime(Instant.now());
sessionToUpdate.setMaxInactiveInterval(Duration.ofSeconds(1));
this.repository.save(sessionToUpdate);
assertThat(this.registry.receivedEvent(sessionToUpdate.getId())).isTrue();
assertThat(this.registry.<SessionExpiredEvent>getEvent(sessionToUpdate.getId()))
.isInstanceOf(SessionExpiredEvent.class);
assertThat(this.repository.findById(sessionToUpdate.getId())).isNull();
}
@Configuration
@EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class HazelcastSessionConfig {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,6 +48,7 @@ import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* A {@link org.springframework.session.SessionRepository} implementation that stores
@@ -120,6 +121,9 @@ public class HazelcastSessionRepository implements
*/
public static final String PRINCIPAL_NAME_ATTRIBUTE = "principalName";
private static final boolean SUPPORTS_SET_TTL = ClassUtils
.hasAtLeastOneMethodWithName(IMap.class, "setTtl");
private static final Log logger = LogFactory.getLog(HazelcastSessionRepository.class);
private final HazelcastInstance hazelcastInstance;
@@ -238,6 +242,9 @@ public class HazelcastSessionRepository implements
entryProcessor.setLastAccessedTime(session.getLastAccessedTime());
}
if (session.maxInactiveIntervalChanged) {
if (SUPPORTS_SET_TTL) {
updateTtl(session);
}
entryProcessor.setMaxInactiveInterval(session.getMaxInactiveInterval());
}
if (!session.delta.isEmpty()) {
@@ -248,6 +255,11 @@ public class HazelcastSessionRepository implements
session.clearChangeFlags();
}
private void updateTtl(HazelcastSession session) {
this.sessions.setTtl(session.getId(),
session.getMaxInactiveInterval().getSeconds(), TimeUnit.SECONDS);
}
@Override
public HazelcastSession findById(String id) {
MapSession saved = this.sessions.get(id);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 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.
@@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
@@ -259,10 +260,12 @@ public class HazelcastSessionRepositoryTests {
this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE);
HazelcastSession session = this.repository.createSession();
String sessionId = session.getId();
session.setMaxInactiveInterval(Duration.ofSeconds(1));
verify(this.sessions, times(1)).set(eq(session.getId()),
verify(this.sessions, times(1)).set(eq(sessionId),
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
verify(this.sessions, times(1)).executeOnKey(eq(session.getId()),
verify(this.sessions).setTtl(eq(sessionId), anyLong(), any());
verify(this.sessions, times(1)).executeOnKey(eq(sessionId),
any(EntryProcessor.class));
this.repository.save(session);

View File

@@ -72,7 +72,7 @@ final class DatabaseContainers {
private static class MariaDb5Container extends MariaDBContainer<MariaDb5Container> {
MariaDb5Container() {
super("mariadb:5.5.62");
super("mariadb:5.5.63");
}
@Override
@@ -103,7 +103,7 @@ final class DatabaseContainers {
private static class MySql5Container extends MySQLContainer<MySql5Container> {
MySql5Container() {
super("mysql:5.7.24");
super("mysql:5.7.25");
}
@Override
@@ -123,7 +123,7 @@ final class DatabaseContainers {
private static class MySql8Container extends MySQLContainer<MySql8Container> {
MySql8Container() {
super("mysql:8.0.13");
super("mysql:8.0.15");
}
@Override
@@ -170,7 +170,7 @@ final class DatabaseContainers {
extends MSSQLServerContainer<SqlServer2017Container> {
SqlServer2017Container() {
super("mcr.microsoft.com/mssql/server:2017-CU12");
super("mcr.microsoft.com/mssql/server:2017-CU13");
}
}

View File

@@ -1 +1 @@
mcr.microsoft.com/mssql/server:2017-CU12
mcr.microsoft.com/mssql/server:2017-CU13