Compare commits

...

36 Commits

Author SHA1 Message Date
Eleftheria Stein
dda13b5619 Release 2.3.0.RC1 2020-03-02 17:02:13 -05:00
Eleftheria Stein
366f13bd25 Upgrade Hazelcast to 3.12.6
Resolves: #1591
2020-03-02 16:29:04 -05:00
Eleftheria Stein
3535137c47 Upgrade test dependencies 2020-03-02 16:28:51 -05:00
Eleftheria Stein
a9bca9088f Upgrade Reactor to Dysprosium-SR5
Resolves: #1590
2020-03-02 16:14:41 -05:00
Eleftheria Stein
31de86ecef Upgrade samples to Spring Boot 2.2.5
Resolves: #1589
2020-03-02 15:46:30 -05:00
Eleftheria Stein
d123960f89 Upgrade Spring Data to Neumann-M3
Resolves: #1588
2020-03-02 15:45:19 -05:00
Eleftheria Stein
16d2923efd Upgrade Spring Security to 5.3.0.RC1
Resolves: #1587
2020-03-02 15:44:49 -05:00
Eleftheria Stein
24015d0854 Upgrade Spring Framework to 5.2.4.RELEASE
Resolves: #1586
2020-03-02 15:43:43 -05:00
Eleftheria Stein
d8f160c178 Update documentation styling
Upgrade spring-build-conventions to 0.0.28.RELEASE

Resolves: #1585
2020-03-02 15:30:29 -05:00
Eleftheria Stein
0318f6e2c1 Fix asciidoctor warnings
Invalid references and mismatched nesting blocks
2020-03-02 09:13:17 -05:00
Eleftheria Stein
43dd571345 Fix typo in Javadoc 2020-02-27 16:32:29 -05:00
Adam Kucera
e7fb9fce47 Fix examples in JavaDocs of classes which use SessionRepositories
The examples in JavaDocs of @EnableSpringHttpSession, SpringHttpSessionConfiguration and @EnableSpringWebSession were creating MapSessionRepository / ReactiveMapSessionRepository
using a constructor, which no longer exists in the classes. This should allow the example
to be used out of the box.
2020-02-20 15:25:46 -05:00
Eleftheria Stein
f13eb8d73e Use Spring Security lambda DSL in samples
Fixes: gh-1580
2020-02-19 12:36:51 +01:00
Jivko Vantchev
1a07ba5114 Fixes the duplicate index name in the example SQL script
The change is in the comments for the JdbcIndexedSessionRepository.
2020-02-14 12:03:24 +01:00
Eleftheria Stein
7125aac567 Next Development Build 2020-01-29 22:18:06 +01:00
Eleftheria Stein
3cbd3a9e25 Release 2.3.0.M1 2020-01-29 21:54:34 +01:00
Eleftheria Stein
4c914d46c9 Upgrade Spring Framework to 5.2.3.RELEASE
Resolves: #1575
2020-01-29 21:47:32 +01:00
Eleftheria Stein
adf411ecc3 Upgrade Spring Security to 5.3.0.M1
Resolves: #1568
2020-01-29 21:12:50 +01:00
Eleftheria Stein
95b39a203f Upgrade Spring Data to Neumann-M2
Resolves: #1567
2020-01-29 21:12:06 +01:00
Eleftheria Stein
3d653b3b50 Next Development Build 2020-01-29 21:08:14 +01:00
Eleftheria Stein
938fd3c2e5 Next Development Build 2020-01-29 20:55:04 +01:00
Eleftheria Stein
45bb0f9b0c Run deployArtifacts before finalizeDeployArtifacts in build
This commit is needed to fix the release

Resolves: #1574
2020-01-29 16:39:07 +01:00
Eleftheria Stein
cddd84d564 Release 2.2.1.RELEASE 2020-01-28 10:57:10 +01:00
Eleftheria Stein
6931d40e6e Upgrade samples to Spring Boot 2.2.4.RELEASE
Resolves: #1563
2020-01-28 10:26:32 +01:00
Eleftheria Stein
3b672787f3 Upgrade Spring Data to Moore-SR4
Resolves: #1564
2020-01-28 10:22:14 +01:00
Eleftheria Stein
c0ee52b33b Upgrade Reactor to Dysprosium-SR4
Resolves: #1565
2020-01-28 10:21:32 +01:00
Eleftheria Stein
68f8641233 Upgrade Spring Security to 5.2.1.RELEASE
Resolves: #1566
2020-01-28 10:20:48 +01:00
Eleftheria Stein
e7b2af47e1 Upgrade Hazelcast to 3.12.5
Resolves: #1569
2020-01-28 10:19:16 +01:00
Eleftheria Stein
1ad6cbd7f8 Update note in custom-cookie index page
Resolves: gh-1559
2020-01-13 11:57:20 +01:00
Rob Winch
195af52d0b Upgrade to Spring Framework 5.2.2.RELEASE
Fixes gh-1548
2019-12-13 07:06:19 -06:00
Vedran Pavic
bc9d5f1299 Start building against Spring Framework 5.2.2.RELEASE snapshots
See: #1548
2019-11-16 10:20:11 +01:00
Vedran Pavic
3a4345eb6a Upgrade Gradle to 5.6.4 2019-11-15 22:23:23 +01:00
Vedran Pavic
6c41dea893 Polish contribution
Resolves: #1543
2019-11-15 22:10:35 +01:00
Eleftheria Stein
ee1d5b3b3c Document support for SameSite cookie directive
See: #1543
2019-11-15 22:06:13 +01:00
Christoph Dreis
89a4255679 Parse expression only once in PrincipalNameIndexResolver
Resolves: #1539
2019-11-15 12:13:42 +01:00
Rob Winch
6d2e51a0b9 Next Development Build 2019-10-15 15:32:01 -05:00
39 changed files with 257 additions and 109 deletions

3
Jenkinsfile vendored
View File

@@ -120,7 +120,8 @@ try {
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')]) {
withEnv(["JAVA_HOME=${tool 'jdk8'}"]) {
sh './gradlew deployArtifacts finalizeDeployArtifacts --no-daemon --stacktrace -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'
sh './gradlew deployArtifacts --no-daemon --stacktrace -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'
sh './gradlew finalizeDeployArtifacts --no-daemon --stacktrace -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'
}
}
}

View File

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

View File

@@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.parallel=true
version=2.2.0.RELEASE
version=2.3.0.RC1

View File

@@ -1,35 +1,35 @@
dependencyManagement {
imports {
mavenBom 'io.projectreactor:reactor-bom:Dysprosium-RELEASE'
mavenBom 'org.junit:junit-bom:5.5.2'
mavenBom 'org.springframework:spring-framework-bom:5.2.0.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Moore-RELEASE'
mavenBom 'org.springframework.security:spring-security-bom:5.2.0.RELEASE'
mavenBom 'io.projectreactor:reactor-bom:Dysprosium-SR5'
mavenBom 'org.junit:junit-bom:5.6.0'
mavenBom 'org.springframework:spring-framework-bom:5.2.4.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Neumann-M3'
mavenBom 'org.springframework.security:spring-security-bom:5.3.0.RC1'
mavenBom 'org.testcontainers:testcontainers-bom:1.12.2'
}
dependencies {
dependencySet(group: 'com.hazelcast', version: '3.12.3') {
dependencySet(group: 'com.hazelcast', version: '3.12.6') {
entry 'hazelcast'
entry 'hazelcast-client'
}
dependency 'com.h2database:h2:1.4.199'
dependency 'com.h2database:h2:1.4.200'
dependency 'com.ibm.db2:jcc:11.5.0.0'
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.4.1.jre8'
dependency 'com.oracle.ojdbc:ojdbc8:19.3.0.0'
dependency 'com.zaxxer:HikariCP:3.4.1'
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
dependency 'io.lettuce:lettuce-core:5.2.0.RELEASE'
dependency 'io.lettuce:lettuce-core:5.2.2.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.17'
dependency 'junit:junit:4.13'
dependency 'mysql:mysql-connector-java:8.0.19'
dependency 'org.apache.derby:derby:10.14.2.0'
dependency 'org.assertj:assertj-core:3.13.2'
dependency 'org.assertj:assertj-core:3.15.0'
dependency 'org.hsqldb:hsqldb:2.5.0'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.4.4'
dependency 'org.mockito:mockito-core:3.0.0'
dependency 'org.postgresql:postgresql:42.2.8'
dependency 'org.mockito:mockito-core:3.3.0'
dependency 'org.postgresql:postgresql:42.2.10'
}
}

View File

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

View File

@@ -32,7 +32,7 @@ public class PrincipalNameIndexResolver<S extends Session> extends SingleIndexRe
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
private static final SpelExpressionParser parser = new SpelExpressionParser();
private static final Expression expression = new SpelExpressionParser().parseExpression("authentication?.name");
public PrincipalNameIndexResolver() {
super(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
@@ -45,7 +45,6 @@ public class PrincipalNameIndexResolver<S extends Session> extends SingleIndexRe
}
Object authentication = session.getAttribute(SPRING_SECURITY_CONTEXT);
if (authentication != null) {
Expression expression = parser.parseExpression("authentication?.name");
return expression.getValue(authentication, String.class);
}
return null;

View File

@@ -40,7 +40,7 @@ import org.springframework.session.events.SessionDestroyedEvent;
*
* {@literal @Bean}
* public MapSessionRepository sessionRepository() {
* return new MapSessionRepository();
* return new MapSessionRepository(new ConcurrentHashMap<>());
* }
*
* }

View File

@@ -58,7 +58,7 @@ import org.springframework.util.ObjectUtils;
*
* {@literal @Bean}
* public MapSessionRepository sessionRepository() {
* return new MapSessionRepository();
* return new MapSessionRepository(new ConcurrentHashMap<>());
* }
*
* }

View File

@@ -36,7 +36,7 @@ import org.springframework.context.annotation.Import;
*
* {@literal @Bean}
* public ReactiveSessionRepository sessionRepository() {
* return new ReactiveMapSessionRepository();
* return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
* }
*
* }

View File

@@ -19,6 +19,8 @@ package org.springframework.session.web.http;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import javax.servlet.http.Cookie;
@@ -28,7 +30,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockCookie;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@@ -52,7 +53,7 @@ class DefaultCookieSerializerTests {
private MockHttpServletRequest request;
private CookiePreservingMockHttpServletResponse response;
private MockHttpServletResponse response;
private DefaultCookieSerializer serializer;
@@ -62,7 +63,7 @@ class DefaultCookieSerializerTests {
void setup() {
this.cookieName = "SESSION";
this.request = new MockHttpServletRequest();
this.response = new CookiePreservingMockHttpServletResponse();
this.response = new MockHttpServletResponse();
this.sessionId = "sessionId";
this.serializer = new DefaultCookieSerializer();
}
@@ -213,14 +214,14 @@ class DefaultCookieSerializerTests {
this.request.setServerName(domain);
this.serializer.writeCookieValue(cookieValue(this.sessionId));
assertThat(getCookie().getDomain()).isEqualTo("example.com");
this.response = new CookiePreservingMockHttpServletResponse();
this.response = new MockHttpServletResponse();
}
String[] notMatchingDomains = { "example.com", "localhost", "127.0.0.1" };
for (String domain : notMatchingDomains) {
this.request.setServerName(domain);
this.serializer.writeCookieValue(cookieValue(this.sessionId));
assertThat(getCookie().getDomain()).isNull();
this.response = new CookiePreservingMockHttpServletResponse();
this.response = new MockHttpServletResponse();
}
}
@@ -291,7 +292,7 @@ class DefaultCookieSerializerTests {
void writeCookieCookieMaxAgeDefault() {
this.serializer.writeCookieValue(cookieValue(this.sessionId));
assertThat(getCookie().getMaxAge()).isEqualTo(-1);
assertThat(this.response.rawCookie).doesNotContain("Expires");
assertThat(getCookie().getExpires()).isNull();
}
@Test
@@ -299,8 +300,11 @@ class DefaultCookieSerializerTests {
this.serializer.setClock(Clock.fixed(Instant.parse("2019-10-07T20:10:00Z"), ZoneOffset.UTC));
this.serializer.setCookieMaxAge(100);
this.serializer.writeCookieValue(cookieValue(this.sessionId));
assertThat(getCookie().getMaxAge()).isEqualTo(100);
assertThat(this.response.rawCookie).contains("Expires=Mon, 7 Oct 2019 20:11:40 GMT");
MockCookie cookie = getCookie();
assertThat(cookie.getMaxAge()).isEqualTo(100);
ZonedDateTime expires = cookie.getExpires();
assertThat(expires).isNotNull();
assertThat(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME)).isEqualTo("Mon, 7 Oct 2019 20:11:40 GMT");
}
@Test
@@ -308,8 +312,11 @@ class DefaultCookieSerializerTests {
this.serializer.setClock(Clock.fixed(Instant.parse("2019-10-07T20:10:00Z"), ZoneOffset.UTC));
this.serializer.setCookieMaxAge(100);
this.serializer.writeCookieValue(cookieValue(""));
assertThat(getCookie().getMaxAge()).isEqualTo(0);
assertThat(this.response.rawCookie).contains("Expires=Thu, 1 Jan 1970 00:00:00 GMT");
MockCookie cookie = getCookie();
assertThat(cookie.getMaxAge()).isEqualTo(0);
ZonedDateTime expires = cookie.getExpires();
assertThat(expires).isNotNull();
assertThat(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME)).isEqualTo("Thu, 1 Jan 1970 00:00:00 GMT");
}
@Test
@@ -318,8 +325,11 @@ class DefaultCookieSerializerTests {
CookieValue cookieValue = cookieValue(this.sessionId);
cookieValue.setCookieMaxAge(100);
this.serializer.writeCookieValue(cookieValue);
assertThat(getCookie().getMaxAge()).isEqualTo(100);
assertThat(this.response.rawCookie).contains("Expires=Mon, 7 Oct 2019 20:11:40 GMT");
MockCookie cookie = getCookie();
assertThat(cookie.getMaxAge()).isEqualTo(100);
ZonedDateTime expires = cookie.getExpires();
assertThat(expires).isNotNull();
assertThat(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME)).isEqualTo("Mon, 7 Oct 2019 20:11:40 GMT");
}
// --- secure ---
@@ -482,18 +492,4 @@ class DefaultCookieSerializerTests {
return new CookieValue(this.request, this.response, cookieValue);
}
private static class CookiePreservingMockHttpServletResponse extends MockHttpServletResponse {
private String rawCookie;
@Override
public void addHeader(String name, String value) {
if (HttpHeaders.SET_COOKIE.equals(name)) {
this.rawCookie = value;
}
super.addHeader(name, value);
}
}
}

View File

@@ -142,7 +142,7 @@ import org.springframework.util.Assert;
* <p>
* When a session is created an event is sent to Redis with the channel of
* "spring:session:channel:created:33fdd1b6-b496-4b33-9f7d-df96679d32fe" such that
* "33fdd1b6-b496-4b33-9f7d-df96679d32fe" is the sesion id. The body of the event will be
* "33fdd1b6-b496-4b33-9f7d-df96679d32fe" is the session id. The body of the event will be
* the session that was created.
* </p>
*

View File

@@ -46,5 +46,7 @@ asciidoctor {
'spring-session-version': project.version,
'version-milestone': milestoneBuild,
'version-release': releaseBuild,
'version-snapshot': snapshotBuild
'version-snapshot': snapshotBuild,
'highlightjsdir@': "js/highlight",
'docinfodir@': "."
}

View File

@@ -1,11 +1,16 @@
= Spring Session - find by username
Rob Winch
:toc:
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session to find sessions by username.
NOTE: You can find the completed guide in the <<findbyusername-sample, findbyusername application>>.
[#index-link]
link:../index.html[Index]
[[findbyusername-assumptions]]
== Assumptions

View File

@@ -1,11 +1,17 @@
= Spring Session - Spring Boot
Rob Winch, Vedran Pavić
:toc:
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session to transparently leverage a relational database to back a web application's `HttpSession` when you use Spring Boot.
NOTE: You can find the completed guide in the <<httpsession-jdbc-boot-sample, httpsession-jdbc-boot sample application>>.
[#index-link]
link:../index.html[Index]
== Updating Dependencies
Before you use Spring Session, you must update your dependencies.

View File

@@ -1,11 +1,17 @@
= Spring Session - Spring Boot
Rob Winch, Vedran Pavić
:toc:
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when you use Spring Boot.
NOTE: You can find the completed guide in the <<boot-sample, boot sample application>>.
[#index-link]
link:../index.html[Index]
== Updating Dependencies
Before you use Spring Session, you must ensure your dependencies.
@@ -151,6 +157,6 @@ To do so, enter the following into your terminal, being sure to replace `7e8383a
----
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
----
=====
====
Now you can visit the application at http://localhost:8080/ and observe that we are no longer authenticated.

View File

@@ -1,7 +1,10 @@
= Spring Session - WebSocket
Rob Winch
:toc:
:toc: left
:websocketdoc-test-dir: {docs-test-dir}docs/websocket/
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session to ensure that WebSocket messages keep your HttpSession alive.
@@ -12,6 +15,9 @@ Specifically,it does not work with using https://www.jcp.org/en/jsr/detail?id=35
// end::disclaimer[]
[#index-link]
link:../index.html[Index]
== HttpSession Setup
The first step is to integrate Spring Session with the HttpSession. These steps are already outlined in the link:httpsession.html[HttpSession Guide].

View File

@@ -0,0 +1,2 @@
<script type="text/javascript" src="../js/tocbot/tocbot.min.js"></script>
<script type="text/javascript" src="../js/toc.js"></script>

View File

@@ -1,12 +1,18 @@
= Spring Session - Custom Cookie
Rob Winch
:toc:
Rob Winch; Eleftheria Stein-Kousathana
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to configure Spring Session to use custom cookies with Java Configuration.
The guide assumes you have already link:./httpsession.html[set up Spring Session in your project].
NOTE: You can find the completed guide in the <<custom-cookie-sample, Custom Cookie sample application>>.
[#index-link]
link:../index.html[Index]
[[custom-cookie-spring-configuration]]
== Spring Java Configuration
@@ -58,6 +64,9 @@ See `domainNamePattern` as an alternative.
The pattern should provide a single grouping that is used to extract the value of the cookie domain.
If the regular expression does not match, no domain is set and the existing domain is used.
If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] is used as the domain.
* `sameSite`: The value for the `SameSite` cookie directive.
To disable the serialization of the `SameSite` cookie directive, you may set this value to `null`.
Default: `Lax`
WARNING: You should only match on valid domain characters, since the domain name is reflected in the response.
Doing so prevents a malicious user from performing such attacks as https://en.wikipedia.org/wiki/HTTP_response_splitting[HTTP Response Splitting].

View File

@@ -1,12 +1,18 @@
= Spring Session and Spring Security with Hazelcast
Tommy Ludwig; Rob Winch
:toc:
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session along with Spring Security when you use Hazelcast as your data store.
It assumes that you have already applied Spring Security to your application.
NOTE: You cand find the completed guide in the <<hazelcast-spring-security-sample, Hazelcast Spring Security sample application>>.
[#index-link]
link:../index.html[Index]
== Updating Dependencies
Before you use Spring Session, you must update your dependencies.

View File

@@ -1,11 +1,17 @@
= Spring Session - HttpSession (Quick Start)
Rob Winch, Vedran Pavić
:toc:
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session to transparently leverage a relational database to back a web application's `HttpSession` with Java Configuration.
NOTE: You can find the completed guide in the <<httpsession-jdbc-sample, httpsession-jdbc sample application>>.
[#index-link]
link:../index.html[Index]
== Updating Dependencies
Before you use Spring Session, you must update your dependencies.
@@ -99,7 +105,7 @@ For additional information on how to configure data access related concerns, see
== Java Servlet Container Initialization
Our <<httpsession-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
Our <<httpsession-jdbc-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
In order for our `Filter` to do its magic, Spring needs to load our `Config` class.

View File

@@ -1,12 +1,18 @@
= Spring Session - HttpSession (Quick Start)
Rob Winch
:toc:
:toc: left
:version-snapshot: true
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` with Java Configuration.
NOTE: You can find the completed guide in the <<httpsession-sample, httpsession sample application>>.
[#index-link]
link:../index.html[Index]
== Updating Dependencies
Before you use Spring Session, you must update your dependencies.
If you are using Maven, you must add the following dependencies:

View File

@@ -1,11 +1,17 @@
= Spring Session - REST
Rob Winch
:toc:
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when you use REST endpoints.
NOTE: You can find the completed guide in the <<rest-sample, rest sample application>>.
[#index-link]
link:../index.html[Index]
== Updating Dependencies
Before you use Spring Session, you must update your dependencies.
@@ -241,7 +247,7 @@ $ curl -v http://localhost:8080/ -u user:password
In the output, you should notice the following:
===
====
----
HTTP/1.1 200 OK
...

View File

@@ -1,12 +1,18 @@
= Spring Session and Spring Security
Rob Winch
:toc:
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session along with Spring Security.
It assumes you have already applied Spring Security to your application.
NOTE: You can find the completed guide in the <<security-sample, security sample application>>.
[#index-link]
link:../index.html[Index]
== Updating Dependencies
Before you use Spring Session, you must update your dependencies.
If you use Maven, you must add the following dependencies:

View File

@@ -1,11 +1,17 @@
= Spring Session - HttpSession (Quick Start)
Rob Winch, Vedran Pavić
:toc:
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session to transparently leverage a relational to back a web application's `HttpSession` with XML based configuration.
NOTE: You can find the completed guide in the <<httpsession-jdbc-xml-sample, httpsession-jdbc-xml sample application>>.
[#index-link]
link:../index.html[Index]
== Updating Dependencies
Before you use Spring Session, you must update your dependencies.
@@ -68,8 +74,8 @@ You must have the following in your pom.xml:
<url>https://repo.spring.io/libs-milestone</url>
</repository>
----
endif::[]
====
endif::[]
// tag::config[]

View File

@@ -1,11 +1,17 @@
= Spring Session - HttpSession (Quick Start)
Rob Winch
:toc:
:toc: left
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` with XML-based configuration.
NOTE: You can find the completed guide in the <<httpsession-xml-sample, httpsession-xml sample application>>.
[#index-link]
link:../index.html[Index]
== Updating Dependencies
Before you use Spring Session, you must update your dependencies.
If you use Maven, you must add the following dependencies:

View File

@@ -1,5 +1,5 @@
= Spring Session
Rob Winch; Vedran Pavić; Jay Bryant
Rob Winch; Vedran Pavić; Jay Bryant; Eleftheria Stein-Kousathana
:doctype: book
:indexdoc-tests: {docs-test-dir}docs/IndexDocTests.java
:websocketdoc-test-dir: {docs-test-dir}docs/websocket/
@@ -596,6 +596,7 @@ You can browse the complete link:../../api/[Javadoc] online. The key APIs are de
* <<api-reactivemapsessionrepository>>
* <<api-jdbcindexedsessionrepository>>
* <<api-hazelcastindexedsessionrepository>>
* <<api-cookieserializer>>
[[api-session]]
=== Using `Session`
@@ -1230,6 +1231,68 @@ Note that if you use Hazelcast's `MapStore` to persist your sessions `IMap`, the
* Reloading triggers `EntryAddedListener` results in `SessionCreatedEvent` being re-published
* Reloading uses default TTL for a given `IMap` results in sessions losing their original TTL
[[api-cookieserializer]]
=== Using `CookieSerializer`
A `CookieSerializer` is responsible for defining how the session cookie is written.
Spring Session comes with a default implementation using `DefaultCookieSerializer`.
[[api-cookieserializer-bean]]
==== Exposing `CookieSerializer` as a bean
Exposing the `CookieSerializer` as a Spring bean augments the existing configuration when you use configurations like `@EnableRedisHttpSession`.
The following example shows how to do so:
====
[source,java]
----
include::{samples-dir}spring-session-sample-javaconfig-custom-cookie/src/main/java/sample/Config.java[tags=cookie-serializer]
----
<1> We customize the name of the cookie to be `JSESSIONID`.
<2> We customize the path of the cookie to be `/` (rather than the default of the context root).
<3> We customize the domain name pattern (a regular expression) to be `^.+?\\.(\\w+\\.[a-z]+)$`.
This allows sharing a session across domains and applications.
If the regular expression does not match, no domain is set and the existing domain is used.
If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] is used as the domain.
This means that a request to https://child.example.com sets the domain to `example.com`.
However, a request to http://localhost:8080/ or https://192.168.1.100:8080/ leaves the cookie unset and, thus, still works in development without any changes being necessary for production.
====
WARNING: You should only match on valid domain characters, since the domain name is reflected in the response.
Doing so prevents a malicious user from performing such attacks as https://en.wikipedia.org/wiki/HTTP_response_splitting[HTTP Response Splitting].
[[api-cookieserializer-customization]]
==== Customizing `CookieSerializer`
You can customize how the session cookie is written by using any of the following configuration options on the `DefaultCookieSerializer`.
* `cookieName`: The name of the cookie to use.
Default: `SESSION`.
* `useSecureCookie`: Specifies whether a secure cookie should be used.
Default: Use the value of `HttpServletRequest.isSecure()` at the time of creation.
* `cookiePath`: The path of the cookie.
Default: The context root.
* `cookieMaxAge`: Specifies the max age of the cookie to be set at the time the session is created.
Default: `-1`, which indicates the cookie should be removed when the browser is closed.
* `jvmRoute`: Specifies a suffix to be appended to the session ID and included in the cookie.
Used to identify which JVM to route to for session affinity.
With some implementations (that is, Redis) this option provides no performance benefit.
However, it can help with tracing logs of a particular user.
* `domainName`: Allows specifying a specific domain name to be used for the cookie.
This option is simple to understand but often requires a different configuration between development and production environments.
See `domainNamePattern` as an alternative.
* `domainNamePattern`: A case-insensitive pattern used to extract the domain name from the `HttpServletRequest#getServerName()`.
The pattern should provide a single grouping that is used to extract the value of the cookie domain.
If the regular expression does not match, no domain is set and the existing domain is used.
If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] is used as the domain.
* `sameSite`: The value for the `SameSite` cookie directive.
To disable the serialization of the `SameSite` cookie directive, you may set this value to `null`.
Default: `Lax`
WARNING: You should only match on valid domain characters, since the domain name is reflected in the response.
Doing so prevents a malicious user from performing such attacks as https://en.wikipedia.org/wiki/HTTP_response_splitting[HTTP Response Splitting].
[[custom-sessionrepository]]
== Customing `SessionRepository`

View File

@@ -19,6 +19,7 @@ package docs.security;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@@ -41,14 +42,16 @@ public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapte
protected void configure(HttpSecurity http) throws Exception {
http
// ... additional configuration ...
.rememberMe()
.rememberMeServices(rememberMeServices());
.rememberMe((rememberMe) -> rememberMe
.rememberMeServices(rememberMeServices())
);
// end::http-rememberme[]
http
.formLogin().and()
.authorizeRequests()
.anyRequest().authenticated();
.formLogin(Customizer.withDefaults())
.authorizeRequests((authorize) -> authorize
.anyRequest().authenticated()
);
}
// tag::rememberme-bean[]

View File

@@ -40,9 +40,10 @@ public class SecurityConfiguration<S extends Session> extends WebSecurityConfigu
// @formatter:off
http
// other config goes here...
.sessionManagement()
.sessionManagement((sessionManagement) -> sessionManagement
.maximumSessions(2)
.sessionRegistry(sessionRegistry());
.sessionRegistry(sessionRegistry())
);
// @formatter:on
}

View File

@@ -103,7 +103,7 @@ import org.springframework.util.StringUtils;
* );
*
* CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
* CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (EXPIRY_TIME);
* CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
* CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);
*
* CREATE TABLE SPRING_SESSION_ATTRIBUTES (

View File

@@ -35,13 +35,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.authorizeRequests((authorize) -> authorize
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
)
.formLogin((formLogin) -> formLogin
.loginPage("/login")
.permitAll();
.permitAll()
);
}
// end::config[]
// @formatter:on

View File

@@ -44,12 +44,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.authorizeRequests((authorize) -> authorize
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
)
.formLogin((formLogin) -> formLogin
.permitAll()
);
}
// end::config[]
// @formatter:on

View File

@@ -34,13 +34,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.authorizeRequests((authorize) -> authorize
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
)
.formLogin((formLogin) -> formLogin
.loginPage("/login")
.permitAll();
.permitAll()
);
}
// @formatter:on

View File

@@ -28,12 +28,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.authorizeRequests((authorize) -> authorize
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
)
.formLogin((formLogin) -> formLogin
.permitAll()
);
}
// @formatter:on

View File

@@ -35,12 +35,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.authorizeRequests((authorize) -> authorize
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
)
.formLogin((formLogin) -> formLogin
.permitAll()
);
}
// end::config[]
// @formatter:on

View File

@@ -53,12 +53,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.authorizeRequests((authorize) -> authorize
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
)
.formLogin((formLogin) -> formLogin
.permitAll()
);
}
// @formatter:on

View File

@@ -15,7 +15,7 @@
<body>
<div class="container">
<h1>Description</h1>
<p>This application demonstrates how to use a Redis instance to back your session. Notice that there is no JSESSIONID cookie. We are also able to customize the way of identifying what the requested session id is.</p>
<p>This application demonstrates how to customize the session cookie. Notice that the name of the cookie is JSESSIONID.</p>
<h1>Try it</h1>

View File

@@ -37,4 +37,4 @@ public class SessionServlet extends HttpServlet {
private static final long serialVersionUID = 2878267318695777395L;
}
// tag::end[]
// end::class[]

View File

@@ -38,4 +38,4 @@ public class SessionServlet extends HttpServlet {
private static final long serialVersionUID = 2878267318695777395L;
}
// tag::end[]
// end::class[]

View File

@@ -17,6 +17,7 @@
package sample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -31,13 +32,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.authorizeRequests((authorize) -> authorize
.anyRequest().authenticated()
.and()
.requestCache()
)
.requestCache((requestCache) -> requestCache
.requestCache(new NullRequestCache())
.and()
.httpBasic();
)
.httpBasic(Customizer.withDefaults());
}
// @formatter:on