Compare commits
12 Commits
2.0.5.RELE
...
2.1.0.M1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bdb3f6ded | ||
|
|
7d3472f55d | ||
|
|
00465a6f00 | ||
|
|
ad35d7ca30 | ||
|
|
18e9ab4c0f | ||
|
|
1c9a6d3e5d | ||
|
|
d2936ed0b4 | ||
|
|
cdf6089ccd | ||
|
|
1ca8a6476a | ||
|
|
cf926045dc | ||
|
|
7123df8656 | ||
|
|
096a5683cb |
15
Jenkinsfile
vendored
15
Jenkinsfile
vendored
@@ -23,21 +23,6 @@ try {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
springio: {
|
||||
stage('Spring IO') {
|
||||
node {
|
||||
checkout scm
|
||||
try {
|
||||
sh "./gradlew clean springIoCheck -PplatformVersion=Cairo-BUILD-SNAPSHOT -PexcludeProjects='**/samples/**' --refresh-dependencies --no-daemon --stacktrace"
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: springio'
|
||||
throw e
|
||||
} finally {
|
||||
junit '**/build/spring-io*-results/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(currentBuild.result == 'SUCCESS') {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -16,16 +16,18 @@
|
||||
|
||||
package docs.security;
|
||||
|
||||
import java.net.HttpCookie;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
@@ -43,6 +45,7 @@ import static org.springframework.security.test.web.servlet.setup.SecurityMockMv
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = RememberMeSecurityConfiguration.class)
|
||||
@@ -78,7 +81,7 @@ public class RememberMeSecurityConfigurationTests<T extends Session> {
|
||||
.andReturn();
|
||||
// @formatter:on
|
||||
|
||||
Cookie cookie = result.getResponse().getCookie("SESSION");
|
||||
HttpCookie cookie = getSessionCookie(result.getResponse());
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
T session = this.sessions
|
||||
.findById(new String(Base64.getDecoder().decode(cookie.getValue())));
|
||||
@@ -86,5 +89,15 @@ public class RememberMeSecurityConfigurationTests<T extends Session> {
|
||||
.isEqualTo(Duration.ofDays(30));
|
||||
|
||||
}
|
||||
|
||||
private HttpCookie getSessionCookie(HttpServletResponse response) {
|
||||
for (HttpCookie cookie : HttpCookie.parse(response.getHeader(HttpHeaders.SET_COOKIE))) {
|
||||
if ("SESSION".equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -16,16 +16,18 @@
|
||||
|
||||
package docs.security;
|
||||
|
||||
import java.net.HttpCookie;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
@@ -43,6 +45,7 @@ import static org.springframework.security.test.web.servlet.setup.SecurityMockMv
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@@ -78,7 +81,7 @@ public class RememberMeSecurityConfigurationXmlTests<T extends Session> {
|
||||
.andReturn();
|
||||
// @formatter:on
|
||||
|
||||
Cookie cookie = result.getResponse().getCookie("SESSION");
|
||||
HttpCookie cookie = getSessionCookie(result.getResponse());
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
T session = this.sessions
|
||||
.findById(new String(Base64.getDecoder().decode(cookie.getValue())));
|
||||
@@ -86,5 +89,15 @@ public class RememberMeSecurityConfigurationXmlTests<T extends Session> {
|
||||
.isEqualTo(Duration.ofDays(30));
|
||||
|
||||
}
|
||||
|
||||
private HttpCookie getSessionCookie(HttpServletResponse response) {
|
||||
for (HttpCookie cookie : HttpCookie.parse(response.getHeader(HttpHeaders.SET_COOKIE))) {
|
||||
if ("SESSION".equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
springBootVersion=2.0.3.RELEASE
|
||||
version=2.0.5.RELEASE
|
||||
version=2.1.0.M1
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.6'
|
||||
mavenBom 'io.projectreactor:reactor-bom:Bismuth-SR10'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.0.8.RELEASE'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-SR9'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.0.7.RELEASE'
|
||||
mavenBom 'io.projectreactor:reactor-bom:Californium-M1'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.1.0.RC1'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Lovelace-RC1'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.1.0.M2'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.8.1'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dependencySet(group: 'com.hazelcast', version: '3.9.4') {
|
||||
dependencySet(group: 'com.hazelcast', version: '3.10.3') {
|
||||
entry 'hazelcast'
|
||||
entry 'hazelcast-client'
|
||||
}
|
||||
@@ -17,7 +17,7 @@ dependencyManagement {
|
||||
dependency 'com.h2database:h2:1.4.197'
|
||||
dependency 'com.microsoft.sqlserver:mssql-jdbc:6.4.0.jre8'
|
||||
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
|
||||
dependency 'io.lettuce:lettuce-core:5.0.4.RELEASE'
|
||||
dependency 'io.lettuce:lettuce-core:5.1.0.M1'
|
||||
dependency 'javax.servlet:javax.servlet-api:3.1.0'
|
||||
dependency 'junit:junit:4.12'
|
||||
dependency 'mysql:mysql-connector-java:8.0.11'
|
||||
|
||||
@@ -16,6 +16,20 @@
|
||||
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -30,8 +44,11 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
|
||||
@@ -96,6 +113,62 @@ public class FindByUsernameTests {
|
||||
redisContainer().getFirstMappedPort());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<SetCookieHandlerFilter> testFilter() {
|
||||
FilterRegistrationBean<SetCookieHandlerFilter> registrationBean = new FilterRegistrationBean<>(
|
||||
new SetCookieHandlerFilter());
|
||||
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SetCookieHandlerFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(
|
||||
httpServletResponse) {
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value) {
|
||||
if (HttpHeaders.SET_COOKIE.equals(name)) {
|
||||
List<HttpCookie> cookies = HttpCookie.parse(value);
|
||||
if (!cookies.isEmpty()) {
|
||||
addCookie(toServletCookie(cookies.get(0)));
|
||||
}
|
||||
}
|
||||
super.setHeader(name, value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
chain.doFilter(request, responseWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
private static Cookie toServletCookie(HttpCookie httpCookie) {
|
||||
Cookie cookie = new Cookie(httpCookie.getName(), httpCookie.getValue());
|
||||
String domain = httpCookie.getDomain();
|
||||
if (domain != null) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge());
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
cookie.setSecure(httpCookie.getSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
return cookie;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -16,6 +16,20 @@
|
||||
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -28,12 +42,18 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@AutoConfigureMockMvc
|
||||
@@ -79,4 +99,65 @@ public class BootTests {
|
||||
login.assertAt();
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<SetCookieHandlerFilter> testFilter() {
|
||||
FilterRegistrationBean<SetCookieHandlerFilter> registrationBean = new FilterRegistrationBean<>(
|
||||
new SetCookieHandlerFilter());
|
||||
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SetCookieHandlerFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(
|
||||
httpServletResponse) {
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value) {
|
||||
if (HttpHeaders.SET_COOKIE.equals(name)) {
|
||||
List<HttpCookie> cookies = HttpCookie.parse(value);
|
||||
if (!cookies.isEmpty()) {
|
||||
addCookie(toServletCookie(cookies.get(0)));
|
||||
}
|
||||
}
|
||||
super.setHeader(name, value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
chain.doFilter(request, responseWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
private static Cookie toServletCookie(HttpCookie httpCookie) {
|
||||
Cookie cookie = new Cookie(httpCookie.getName(), httpCookie.getValue());
|
||||
String domain = httpCookie.getDomain();
|
||||
if (domain != null) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge());
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
cookie.setSecure(httpCookie.getSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
return cookie;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,20 @@
|
||||
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -33,8 +45,11 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
|
||||
@@ -120,6 +135,62 @@ public class HttpRedisJsonTest {
|
||||
redisContainer().getFirstMappedPort());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<SetCookieHandlerFilter> testFilter() {
|
||||
FilterRegistrationBean<SetCookieHandlerFilter> registrationBean = new FilterRegistrationBean<>(
|
||||
new SetCookieHandlerFilter());
|
||||
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SetCookieHandlerFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(
|
||||
httpServletResponse) {
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value) {
|
||||
if (HttpHeaders.SET_COOKIE.equals(name)) {
|
||||
List<HttpCookie> cookies = HttpCookie.parse(value);
|
||||
if (!cookies.isEmpty()) {
|
||||
addCookie(toServletCookie(cookies.get(0)));
|
||||
}
|
||||
}
|
||||
super.setHeader(name, value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
chain.doFilter(request, responseWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
private static Cookie toServletCookie(HttpCookie httpCookie) {
|
||||
Cookie cookie = new Cookie(httpCookie.getName(), httpCookie.getValue());
|
||||
String domain = httpCookie.getDomain();
|
||||
if (domain != null) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge());
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
cookie.setSecure(httpCookie.getSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
return cookie;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,20 @@
|
||||
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -30,8 +44,11 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
|
||||
@@ -102,6 +119,62 @@ public class BootTests {
|
||||
redisContainer().getFirstMappedPort());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<SetCookieHandlerFilter> testFilter() {
|
||||
FilterRegistrationBean<SetCookieHandlerFilter> registrationBean = new FilterRegistrationBean<>(
|
||||
new SetCookieHandlerFilter());
|
||||
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SetCookieHandlerFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(
|
||||
httpServletResponse) {
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value) {
|
||||
if (HttpHeaders.SET_COOKIE.equals(name)) {
|
||||
List<HttpCookie> cookies = HttpCookie.parse(value);
|
||||
if (!cookies.isEmpty()) {
|
||||
addCookie(toServletCookie(cookies.get(0)));
|
||||
}
|
||||
}
|
||||
super.setHeader(name, value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
chain.doFilter(request, responseWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
private static Cookie toServletCookie(HttpCookie httpCookie) {
|
||||
Cookie cookie = new Cookie(httpCookie.getName(), httpCookie.getValue());
|
||||
String domain = httpCookie.getDomain();
|
||||
if (domain != null) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge());
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
cookie.setSecure(httpCookie.getSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
return cookie;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -36,7 +36,7 @@ public class LoginPage extends BasePage {
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Please sign in");
|
||||
}
|
||||
|
||||
public Form form() {
|
||||
@@ -51,7 +51,7 @@ public class LoginPage extends BasePage {
|
||||
@FindBy(name = "password")
|
||||
private WebElement password;
|
||||
|
||||
@FindBy(name = "submit")
|
||||
@FindBy(tagName = "button")
|
||||
private WebElement button;
|
||||
|
||||
public Form(SearchContext context) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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,7 +34,7 @@ public class LoginPage extends BasePage {
|
||||
@FindBy(name = "password")
|
||||
private WebElement password;
|
||||
|
||||
@FindBy(css = "input[type='submit']")
|
||||
@FindBy(tagName = "button")
|
||||
private WebElement button;
|
||||
|
||||
public LoginPage(WebDriver driver) {
|
||||
@@ -47,7 +47,7 @@ public class LoginPage extends BasePage {
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
|
||||
assertThat(getDriver().getTitle()).isEqualTo("Please sign in");
|
||||
}
|
||||
|
||||
public HomePage login(String user, String password) {
|
||||
|
||||
@@ -132,10 +132,6 @@ public final class MapSession implements Session, Serializable {
|
||||
return this.originalId;
|
||||
}
|
||||
|
||||
void setOriginalId(String originalId) {
|
||||
this.originalId = originalId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
String changedId = generateId();
|
||||
|
||||
@@ -73,7 +73,6 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
public void save(MapSession session) {
|
||||
if (!session.getId().equals(session.getOriginalId())) {
|
||||
this.sessions.remove(session.getOriginalId());
|
||||
session.setOriginalId(session.getId());
|
||||
}
|
||||
this.sessions.put(session.getId(), new MapSession(session));
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@ public class ReactiveMapSessionRepository implements ReactiveSessionRepository<M
|
||||
return Mono.fromRunnable(() -> {
|
||||
if (!session.getId().equals(session.getOriginalId())) {
|
||||
this.sessions.remove(session.getOriginalId());
|
||||
session.setOriginalId(session.getId());
|
||||
}
|
||||
this.sessions.put(session.getId(), new MapSession(session));
|
||||
});
|
||||
|
||||
@@ -16,8 +16,13 @@
|
||||
|
||||
package org.springframework.session.web.http;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -41,6 +46,22 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DefaultCookieSerializer.class);
|
||||
|
||||
private static final BitSet domainValid = new BitSet(128);
|
||||
|
||||
static {
|
||||
for (char c = '0'; c <= '9'; c++) {
|
||||
domainValid.set(c);
|
||||
}
|
||||
for (char c = 'a'; c <= 'z'; c++) {
|
||||
domainValid.set(c);
|
||||
}
|
||||
for (char c = 'A'; c <= 'Z'; c++) {
|
||||
domainValid.set(c);
|
||||
}
|
||||
domainValid.set('.');
|
||||
domainValid.set('-');
|
||||
}
|
||||
|
||||
private String cookieName = "SESSION";
|
||||
|
||||
private Boolean useSecureCookie;
|
||||
@@ -61,6 +82,8 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
|
||||
private String rememberMeRequestAttribute;
|
||||
|
||||
private String sameSite = "Lax";
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -75,7 +98,8 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (this.cookieName.equals(cookie.getName())) {
|
||||
String sessionId = (this.useBase64Encoding
|
||||
? base64Decode(cookie.getValue()) : cookie.getValue());
|
||||
? base64Decode(cookie.getValue())
|
||||
: cookie.getValue());
|
||||
if (sessionId == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -101,37 +125,43 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
HttpServletRequest request = cookieValue.getRequest();
|
||||
HttpServletResponse response = cookieValue.getResponse();
|
||||
|
||||
String requestedCookieValue = cookieValue.getCookieValue();
|
||||
String actualCookieValue = (this.jvmRoute != null
|
||||
? requestedCookieValue + this.jvmRoute : requestedCookieValue);
|
||||
|
||||
Cookie sessionCookie = new Cookie(this.cookieName, this.useBase64Encoding
|
||||
? base64Encode(actualCookieValue) : actualCookieValue);
|
||||
sessionCookie.setSecure(isSecureCookie(request));
|
||||
sessionCookie.setPath(getCookiePath(request));
|
||||
String domainName = getDomainName(request);
|
||||
if (domainName != null) {
|
||||
sessionCookie.setDomain(domainName);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.cookieName).append('=');
|
||||
String value = getValue(cookieValue);
|
||||
if (value != null && value.length() > 0) {
|
||||
validateValue(value);
|
||||
sb.append(value);
|
||||
}
|
||||
int maxAge = getMaxAge(cookieValue);
|
||||
if (maxAge > -1) {
|
||||
sb.append("; Max-Age=").append(cookieValue.getCookieMaxAge());
|
||||
OffsetDateTime expires = (maxAge != 0
|
||||
? OffsetDateTime.now().plusSeconds(maxAge)
|
||||
: Instant.EPOCH.atOffset(ZoneOffset.UTC));
|
||||
sb.append("; Expires=")
|
||||
.append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||
}
|
||||
String domain = getDomainName(request);
|
||||
if (domain != null && domain.length() > 0) {
|
||||
validateDomain(domain);
|
||||
sb.append("; Domain=").append(domain);
|
||||
}
|
||||
String path = getCookiePath(request);
|
||||
if (path != null && path.length() > 0) {
|
||||
validatePath(path);
|
||||
sb.append("; Path=").append(path);
|
||||
}
|
||||
if (isSecureCookie(request)) {
|
||||
sb.append("; Secure");
|
||||
}
|
||||
|
||||
if (this.useHttpOnlyCookie) {
|
||||
sessionCookie.setHttpOnly(true);
|
||||
sb.append("; HttpOnly");
|
||||
}
|
||||
if (this.sameSite != null) {
|
||||
sb.append("; SameSite=").append(this.sameSite);
|
||||
}
|
||||
|
||||
if (cookieValue.getCookieMaxAge() < 0) {
|
||||
if (this.rememberMeRequestAttribute != null
|
||||
&& request.getAttribute(this.rememberMeRequestAttribute) != null) {
|
||||
// the cookie is only written at time of session creation, so we rely on
|
||||
// session expiration rather than cookie expiration if remember me is enabled
|
||||
cookieValue.setCookieMaxAge(Integer.MAX_VALUE);
|
||||
}
|
||||
else if (this.cookieMaxAge != null) {
|
||||
cookieValue.setCookieMaxAge(this.cookieMaxAge);
|
||||
}
|
||||
}
|
||||
sessionCookie.setMaxAge(cookieValue.getCookieMaxAge());
|
||||
|
||||
response.addCookie(sessionCookie);
|
||||
response.addHeader("Set-Cookie", sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,6 +192,81 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
return new String(encodedCookieBytes);
|
||||
}
|
||||
|
||||
private String getValue(CookieValue cookieValue) {
|
||||
String requestedCookieValue = cookieValue.getCookieValue();
|
||||
String actualCookieValue = requestedCookieValue;
|
||||
if (this.jvmRoute != null) {
|
||||
actualCookieValue = requestedCookieValue + this.jvmRoute;
|
||||
}
|
||||
if (this.useBase64Encoding) {
|
||||
actualCookieValue = base64Encode(actualCookieValue);
|
||||
}
|
||||
return actualCookieValue;
|
||||
}
|
||||
|
||||
private void validateValue(String value) {
|
||||
int start = 0;
|
||||
int end = value.length();
|
||||
if ((end > 1) && (value.charAt(0) == '"') && (value.charAt(end - 1) == '"')) {
|
||||
start = 1;
|
||||
end--;
|
||||
}
|
||||
char[] chars = value.toCharArray();
|
||||
for (int i = start; i < end; i++) {
|
||||
char c = chars[i];
|
||||
if (c < 0x21 || c == 0x22 || c == 0x2c || c == 0x3b || c == 0x5c
|
||||
|| c == 0x7f) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid character in cookie value: " + Integer.toString(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getMaxAge(CookieValue cookieValue) {
|
||||
int maxAge = cookieValue.getCookieMaxAge();
|
||||
if (maxAge < 0) {
|
||||
if (this.rememberMeRequestAttribute != null && cookieValue.getRequest()
|
||||
.getAttribute(this.rememberMeRequestAttribute) != null) {
|
||||
// the cookie is only written at time of session creation, so we rely on
|
||||
// session expiration rather than cookie expiration if remember me is
|
||||
// enabled
|
||||
cookieValue.setCookieMaxAge(Integer.MAX_VALUE);
|
||||
}
|
||||
else if (this.cookieMaxAge != null) {
|
||||
cookieValue.setCookieMaxAge(this.cookieMaxAge);
|
||||
}
|
||||
}
|
||||
return cookieValue.getCookieMaxAge();
|
||||
}
|
||||
|
||||
private void validateDomain(String domain) {
|
||||
int i = 0;
|
||||
int cur = -1;
|
||||
int prev;
|
||||
char[] chars = domain.toCharArray();
|
||||
while (i < chars.length) {
|
||||
prev = cur;
|
||||
cur = chars[i];
|
||||
if (!domainValid.get(cur)
|
||||
|| ((prev == '.' || prev == -1) && (cur == '.' || cur == '-'))
|
||||
|| (prev == '-' && cur == '.')) {
|
||||
throw new IllegalArgumentException("Invalid cookie domain: " + domain);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (cur == '.' || cur == '-') {
|
||||
throw new IllegalArgumentException("Invalid cookie domain: " + domain);
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePath(String path) {
|
||||
for (char ch : path.toCharArray()) {
|
||||
if (ch < 0x20 || ch > 0x7E || ch == ';') {
|
||||
throw new IllegalArgumentException("Invalid cookie path: " + path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if a Cookie marked as secure should be used. The default is to use the value
|
||||
* of {@link HttpServletRequest#isSecure()}.
|
||||
@@ -317,6 +422,16 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
this.rememberMeRequestAttribute = rememberMeRequestAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code SameSite} cookie directive. The default value is
|
||||
* {@code Lax}.
|
||||
* @param sameSite the SameSite directive value
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public void setSameSite(String sameSite) {
|
||||
this.sameSite = sameSite;
|
||||
}
|
||||
|
||||
private String getDomainName(HttpServletRequest request) {
|
||||
if (this.domainName != null) {
|
||||
return this.domainName;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -24,8 +24,13 @@ import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpSessionBindingEvent;
|
||||
import javax.servlet.http.HttpSessionBindingListener;
|
||||
import javax.servlet.http.HttpSessionContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.session.Session;
|
||||
|
||||
/**
|
||||
@@ -33,11 +38,14 @@ import org.springframework.session.Session;
|
||||
*
|
||||
* @param <S> the {@link Session} type
|
||||
* @author Rob Winch
|
||||
* @author Vedran Pavic
|
||||
* @since 1.1
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(HttpSessionAdapter.class);
|
||||
|
||||
private S session;
|
||||
|
||||
private final ServletContext servletContext;
|
||||
@@ -129,7 +137,28 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
@Override
|
||||
public void setAttribute(String name, Object value) {
|
||||
checkState();
|
||||
Object oldValue = this.session.getAttribute(name);
|
||||
this.session.setAttribute(name, value);
|
||||
if (value != oldValue) {
|
||||
if (oldValue instanceof HttpSessionBindingListener) {
|
||||
try {
|
||||
((HttpSessionBindingListener) oldValue).valueUnbound(
|
||||
new HttpSessionBindingEvent(this, name, oldValue));
|
||||
}
|
||||
catch (Throwable th) {
|
||||
logger.error("Error invoking session binding event listener", th);
|
||||
}
|
||||
}
|
||||
if (value instanceof HttpSessionBindingListener) {
|
||||
try {
|
||||
((HttpSessionBindingListener) value)
|
||||
.valueBound(new HttpSessionBindingEvent(this, name, value));
|
||||
}
|
||||
catch (Throwable th) {
|
||||
logger.error("Error invoking session binding event listener", th);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -140,7 +169,17 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
checkState();
|
||||
Object oldValue = this.session.getAttribute(name);
|
||||
this.session.removeAttribute(name);
|
||||
if (oldValue instanceof HttpSessionBindingListener) {
|
||||
try {
|
||||
((HttpSessionBindingListener) oldValue)
|
||||
.valueUnbound(new HttpSessionBindingEvent(this, name, oldValue));
|
||||
}
|
||||
catch (Throwable th) {
|
||||
logger.error("Error invoking session binding event listener", th);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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,12 +18,14 @@ package org.springframework.session.web.http;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.session.MapSession;
|
||||
@@ -83,7 +85,7 @@ public class CookieHttpSessionIdResolverTests {
|
||||
this.strategy.setSessionId(this.request, this.response, this.session.getId());
|
||||
this.strategy.setSessionId(this.request, this.response, this.session.getId());
|
||||
|
||||
assertThat(this.response.getCookies()).hasSize(1);
|
||||
assertThat(this.response.getHeaders("Set-Cookie")).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,11 +95,12 @@ public class CookieHttpSessionIdResolverTests {
|
||||
this.strategy.setSessionId(this.request, this.response, this.session.getId());
|
||||
this.strategy.setSessionId(this.request, this.response, newSession.getId());
|
||||
|
||||
Cookie[] cookies = this.response.getCookies();
|
||||
List<ResponseCookie> cookies = ResponseCookieParser.parse(this.response);
|
||||
assertThat(cookies).hasSize(2);
|
||||
|
||||
assertThat(base64Decode(cookies[0].getValue())).isEqualTo(this.session.getId());
|
||||
assertThat(base64Decode(cookies[1].getValue())).isEqualTo(newSession.getId());
|
||||
assertThat(base64Decode(cookies.get(0).getValue()))
|
||||
.isEqualTo(this.session.getId());
|
||||
assertThat(base64Decode(cookies.get(1).getValue())).isEqualTo(newSession.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -105,7 +108,7 @@ public class CookieHttpSessionIdResolverTests {
|
||||
this.request.setContextPath("/somethingunique");
|
||||
this.strategy.setSessionId(this.request, this.response, this.session.getId());
|
||||
|
||||
Cookie sessionCookie = this.response.getCookie(this.cookieName);
|
||||
ResponseCookie sessionCookie = getCookie();
|
||||
assertThat(sessionCookie.getPath())
|
||||
.isEqualTo(this.request.getContextPath() + "/");
|
||||
}
|
||||
@@ -128,7 +131,7 @@ public class CookieHttpSessionIdResolverTests {
|
||||
this.request.setContextPath("/somethingunique");
|
||||
this.strategy.expireSession(this.request, this.response);
|
||||
|
||||
Cookie sessionCookie = this.response.getCookie(this.cookieName);
|
||||
ResponseCookie sessionCookie = getCookie();
|
||||
assertThat(sessionCookie.getPath())
|
||||
.isEqualTo(this.request.getContextPath() + "/");
|
||||
}
|
||||
@@ -173,8 +176,12 @@ public class CookieHttpSessionIdResolverTests {
|
||||
this.request.setCookies(new Cookie(this.cookieName, base64Encode(value)));
|
||||
}
|
||||
|
||||
private ResponseCookie getCookie() {
|
||||
return ResponseCookieParser.parse(this.response, this.cookieName);
|
||||
}
|
||||
|
||||
private String getSessionId() {
|
||||
return base64Decode(this.response.getCookie(this.cookieName).getValue());
|
||||
return base64Decode(getCookie().getValue());
|
||||
}
|
||||
|
||||
private static String base64Encode(String value) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.session.web.http.CookieSerializer.CookieValue;
|
||||
@@ -324,7 +325,7 @@ public class DefaultCookieSerializerTests {
|
||||
public void writeCookieCookieMaxAgeDefault() {
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getMaxAge()).isEqualTo(-1);
|
||||
assertThat(getCookie().getMaxAge().getSeconds()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -333,7 +334,7 @@ public class DefaultCookieSerializerTests {
|
||||
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getMaxAge()).isEqualTo(100);
|
||||
assertThat(getCookie().getMaxAge().getSeconds()).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -342,7 +343,7 @@ public class DefaultCookieSerializerTests {
|
||||
|
||||
this.serializer.writeCookieValue(cookieValue(""));
|
||||
|
||||
assertThat(getCookie().getMaxAge()).isEqualTo(0);
|
||||
assertThat(getCookie().getMaxAge().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -352,7 +353,7 @@ public class DefaultCookieSerializerTests {
|
||||
|
||||
this.serializer.writeCookieValue(cookieValue);
|
||||
|
||||
assertThat(getCookie().getMaxAge()).isEqualTo(100);
|
||||
assertThat(getCookie().getMaxAge().getSeconds()).isEqualTo(100);
|
||||
}
|
||||
|
||||
// --- secure ---
|
||||
@@ -361,7 +362,7 @@ public class DefaultCookieSerializerTests {
|
||||
public void writeCookieDefaultInsecureRequest() {
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSecure()).isFalse();
|
||||
assertThat(getCookie().isSecure()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -371,7 +372,7 @@ public class DefaultCookieSerializerTests {
|
||||
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSecure()).isTrue();
|
||||
assertThat(getCookie().isSecure()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -380,7 +381,7 @@ public class DefaultCookieSerializerTests {
|
||||
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSecure()).isTrue();
|
||||
assertThat(getCookie().isSecure()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -390,7 +391,7 @@ public class DefaultCookieSerializerTests {
|
||||
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSecure()).isFalse();
|
||||
assertThat(getCookie().isSecure()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -399,7 +400,7 @@ public class DefaultCookieSerializerTests {
|
||||
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSecure()).isFalse();
|
||||
assertThat(getCookie().isSecure()).isFalse();
|
||||
}
|
||||
|
||||
// --- jvmRoute ---
|
||||
@@ -452,7 +453,7 @@ public class DefaultCookieSerializerTests {
|
||||
this.serializer.setRememberMeRequestAttribute("rememberMe");
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
assertThat(getCookie().getMaxAge().getSeconds()).isEqualTo(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -463,7 +464,40 @@ public class DefaultCookieSerializerTests {
|
||||
cookieValue.setCookieMaxAge(100);
|
||||
this.serializer.writeCookieValue(cookieValue);
|
||||
|
||||
assertThat(getCookie().getMaxAge()).isEqualTo(100);
|
||||
assertThat(getCookie().getMaxAge().getSeconds()).isEqualTo(100);
|
||||
}
|
||||
|
||||
// --- sameSite ---
|
||||
|
||||
@Test
|
||||
public void writeCookieDefaultSameSiteLax() {
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSameSite()).isEqualTo("Lax");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeCookieSetSameSiteLax() {
|
||||
this.serializer.setSameSite("Lax");
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSameSite()).isEqualTo("Lax");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeCookieSetSameSiteStrict() {
|
||||
this.serializer.setSameSite("Strict");
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSameSite()).isEqualTo("Strict");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeCookieSetSameSiteNull() {
|
||||
this.serializer.setSameSite(null);
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getSameSite()).isNull();
|
||||
}
|
||||
|
||||
public void setCookieName(String cookieName) {
|
||||
@@ -478,8 +512,8 @@ public class DefaultCookieSerializerTests {
|
||||
return new Cookie(name, value);
|
||||
}
|
||||
|
||||
private Cookie getCookie() {
|
||||
return this.response.getCookie(this.cookieName);
|
||||
private ResponseCookie getCookie() {
|
||||
return ResponseCookieParser.parse(this.response, this.cookieName);
|
||||
}
|
||||
|
||||
private String getCookieValue() {
|
||||
@@ -487,9 +521,6 @@ public class DefaultCookieSerializerTests {
|
||||
if (!this.useBase64Encoding) {
|
||||
return value;
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return new String(Base64.getDecoder().decode(value));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.web.http;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
final class ResponseCookieParser {
|
||||
|
||||
private ResponseCookieParser() {
|
||||
}
|
||||
|
||||
static List<ResponseCookie> parse(HttpServletResponse response) {
|
||||
return doParse(response, null);
|
||||
}
|
||||
|
||||
static ResponseCookie parse(HttpServletResponse response, String cookieName) {
|
||||
List<ResponseCookie> responseCookies = doParse(response, cookieName);
|
||||
return (!responseCookies.isEmpty() ? responseCookies.get(0) : null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static List<ResponseCookie> doParse(HttpServletResponse response,
|
||||
String cookieName) {
|
||||
List<ResponseCookie> responseCookies = new ArrayList<>();
|
||||
for (String setCookieHeader : response.getHeaders(HttpHeaders.SET_COOKIE)) {
|
||||
String[] cookieParts = setCookieHeader.split("\\s*=\\s*", 2);
|
||||
if (cookieParts.length != 2) {
|
||||
return null;
|
||||
}
|
||||
String name = cookieParts[0];
|
||||
if (cookieName != null && !name.equals(cookieName)) {
|
||||
continue;
|
||||
}
|
||||
String[] valueAndDirectives = cookieParts[1].split("\\s*;\\s*", 2);
|
||||
String value = valueAndDirectives[0];
|
||||
String[] directives = valueAndDirectives[1].split("\\s*;\\s*");
|
||||
String domain = null;
|
||||
int maxAge = -1;
|
||||
String path = null;
|
||||
boolean secure = false;
|
||||
boolean httpOnly = false;
|
||||
String sameSite = null;
|
||||
for (String directive : directives) {
|
||||
if (directive.startsWith("Domain")) {
|
||||
domain = directive.split("=")[1];
|
||||
}
|
||||
if (directive.startsWith("Max-Age")) {
|
||||
maxAge = Integer.parseInt(directive.split("=")[1]);
|
||||
}
|
||||
if (directive.startsWith("Path")) {
|
||||
path = directive.split("=")[1];
|
||||
}
|
||||
if (directive.startsWith("Secure")) {
|
||||
secure = true;
|
||||
}
|
||||
if (directive.startsWith("HttpOnly")) {
|
||||
httpOnly = true;
|
||||
}
|
||||
if (directive.startsWith("SameSite")) {
|
||||
sameSite = directive.split("=")[1];
|
||||
}
|
||||
}
|
||||
responseCookies.add(ResponseCookie.from(name, value).maxAge(maxAge).path(path)
|
||||
.domain(domain).secure(secure).httpOnly(httpOnly).sameSite(sameSite)
|
||||
.build());
|
||||
}
|
||||
return responseCookies;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,8 @@ import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletContext;
|
||||
@@ -36,6 +38,8 @@ import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpSessionBindingEvent;
|
||||
import javax.servlet.http.HttpSessionBindingListener;
|
||||
import javax.servlet.http.HttpSessionContext;
|
||||
|
||||
import org.assertj.core.data.Offset;
|
||||
@@ -47,6 +51,7 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@@ -419,7 +424,7 @@ public class SessionRepositoryFilterTests {
|
||||
}
|
||||
});
|
||||
|
||||
assertThat(this.response.getCookie("SESSION")).isNull();
|
||||
assertThat(getSessionCookie()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -437,7 +442,7 @@ public class SessionRepositoryFilterTests {
|
||||
wrappedRequest.getSession();
|
||||
}
|
||||
});
|
||||
assertThat(this.response.getCookie("SESSION")).isNotNull();
|
||||
assertThat(getSessionCookie()).isNotNull();
|
||||
|
||||
nextRequest();
|
||||
|
||||
@@ -449,7 +454,7 @@ public class SessionRepositoryFilterTests {
|
||||
}
|
||||
});
|
||||
|
||||
assertThat(this.response.getCookie("SESSION")).isNotNull();
|
||||
assertThat(getSessionCookie()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -649,10 +654,10 @@ public class SessionRepositoryFilterTests {
|
||||
}
|
||||
});
|
||||
|
||||
Cookie session = getSessionCookie();
|
||||
ResponseCookie session = getSessionCookie();
|
||||
assertThat(session.isHttpOnly()).describedAs("Session Cookie should be HttpOnly")
|
||||
.isTrue();
|
||||
assertThat(session.getSecure())
|
||||
assertThat(session.isSecure())
|
||||
.describedAs("Session Cookie should be marked as Secure").isTrue();
|
||||
}
|
||||
|
||||
@@ -1386,16 +1391,132 @@ public class SessionRepositoryFilterTests {
|
||||
.hasMessage("httpSessionIdResolver cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindListener() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindListenerThenUnbind() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
session.removeAttribute(bindingListenerName);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindSameListenerTwice() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindListenerOverwrite() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener1 = new CountingHttpSessionBindingListener();
|
||||
CountingHttpSessionBindingListener bindingListener2 = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener1);
|
||||
session.setAttribute(bindingListenerName, bindingListener2);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener1.getCounter()).isEqualTo(0);
|
||||
assertThat(bindingListener2.getCounter()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindThrowsException() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
bindingListener.setThrowException();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingListenerBindListenerThenUnbindThrowsException() throws Exception {
|
||||
String bindingListenerName = "bindingListener";
|
||||
CountingHttpSessionBindingListener bindingListener = new CountingHttpSessionBindingListener();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setAttribute(bindingListenerName, bindingListener);
|
||||
bindingListener.setThrowException();
|
||||
session.removeAttribute(bindingListenerName);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assertThat(bindingListener.getCounter()).isEqualTo(1);
|
||||
}
|
||||
|
||||
// --- helper methods
|
||||
|
||||
private void assertNewSession() {
|
||||
Cookie cookie = getSessionCookie();
|
||||
ResponseCookie cookie = getSessionCookie();
|
||||
assertThat(cookie).isNotNull();
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(-1);
|
||||
assertThat(cookie.getMaxAge().getSeconds()).isEqualTo(-1);
|
||||
assertThat(cookie.getValue()).isNotEqualTo("INVALID");
|
||||
assertThat(cookie.isHttpOnly()).describedAs("Cookie is expected to be HTTP Only")
|
||||
.isTrue();
|
||||
assertThat(cookie.getSecure())
|
||||
assertThat(cookie.isSecure())
|
||||
.describedAs(
|
||||
"Cookie secured is expected to be " + this.request.isSecure())
|
||||
.isEqualTo(this.request.isSecure());
|
||||
@@ -1405,15 +1526,15 @@ public class SessionRepositoryFilterTests {
|
||||
}
|
||||
|
||||
private void assertNoSession() {
|
||||
Cookie cookie = getSessionCookie();
|
||||
ResponseCookie cookie = getSessionCookie();
|
||||
assertThat(cookie).isNull();
|
||||
assertThat(this.request.getSession(false))
|
||||
.describedAs("The original HttpServletRequest HttpSession should be null")
|
||||
.isNull();
|
||||
}
|
||||
|
||||
private Cookie getSessionCookie() {
|
||||
return this.response.getCookie("SESSION");
|
||||
private ResponseCookie getSessionCookie() {
|
||||
return ResponseCookieParser.parse(this.response, "SESSION");
|
||||
}
|
||||
|
||||
private void setSessionCookie(String sessionId) {
|
||||
@@ -1436,6 +1557,9 @@ public class SessionRepositoryFilterTests {
|
||||
for (Cookie cookie : this.response.getCookies()) {
|
||||
nameToCookie.put(cookie.getName(), cookie);
|
||||
}
|
||||
ResponseCookieParser.parse(this.response)
|
||||
.forEach((responseCookie) -> nameToCookie.put(responseCookie.getName(),
|
||||
toServletCookie(responseCookie)));
|
||||
Cookie[] nextRequestCookies = new ArrayList<>(nameToCookie.values())
|
||||
.toArray(new Cookie[0]);
|
||||
|
||||
@@ -1466,6 +1590,19 @@ public class SessionRepositoryFilterTests {
|
||||
return new String(Base64.getDecoder().decode(value));
|
||||
}
|
||||
|
||||
private static Cookie toServletCookie(ResponseCookie responseCookie) {
|
||||
Cookie cookie = new Cookie(responseCookie.getName(), responseCookie.getValue());
|
||||
String domain = responseCookie.getDomain();
|
||||
if (domain != null) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setMaxAge((int) responseCookie.getMaxAge().getSeconds());
|
||||
cookie.setPath(responseCookie.getPath());
|
||||
cookie.setSecure(responseCookie.isSecure());
|
||||
cookie.setHttpOnly(responseCookie.isHttpOnly());
|
||||
return cookie;
|
||||
}
|
||||
|
||||
private static class SessionRepositoryFilterDefaultOrder implements Ordered {
|
||||
|
||||
@Override
|
||||
@@ -1488,4 +1625,39 @@ public class SessionRepositoryFilterTests {
|
||||
|
||||
}
|
||||
|
||||
private static class CountingHttpSessionBindingListener
|
||||
implements HttpSessionBindingListener {
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger(0);
|
||||
|
||||
private final AtomicBoolean throwException = new AtomicBoolean(false);
|
||||
|
||||
@Override
|
||||
public void valueBound(HttpSessionBindingEvent event) {
|
||||
if (this.throwException.get()) {
|
||||
this.throwException.compareAndSet(true, false);
|
||||
throw new RuntimeException("bind exception");
|
||||
}
|
||||
this.counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueUnbound(HttpSessionBindingEvent event) {
|
||||
if (this.throwException.get()) {
|
||||
this.throwException.compareAndSet(true, false);
|
||||
throw new RuntimeException("unbind exception");
|
||||
}
|
||||
this.counter.decrementAndGet();
|
||||
}
|
||||
|
||||
int getCounter() {
|
||||
return this.counter.get();
|
||||
}
|
||||
|
||||
void setThrowException() {
|
||||
this.throwException.compareAndSet(false, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
||||
public class HazelcastClientRepositoryITests extends AbstractHazelcastRepositoryITests {
|
||||
|
||||
private static GenericContainer container = new GenericContainer<>(
|
||||
"hazelcast/hazelcast:3.9.4")
|
||||
"hazelcast/hazelcast:3.10.3")
|
||||
.withExposedPorts(5701)
|
||||
.withEnv("JAVA_OPTS",
|
||||
"-Dhazelcast.config=/opt/hazelcast/config_ext/hazelcast.xml")
|
||||
|
||||
Reference in New Issue
Block a user