diff --git a/docs/src/docs/asciidoc/guides/java-users.adoc b/docs/src/docs/asciidoc/guides/java-users.adoc deleted file mode 100644 index 890d43dc..00000000 --- a/docs/src/docs/asciidoc/guides/java-users.adoc +++ /dev/null @@ -1,162 +0,0 @@ -= Spring Session - Multiple Sessions -Rob Winch -:toc: - -This guide describes how to use Spring Session to manage multiple simultaneous browser sessions (i.e Google Accounts). - -== Integrating with Spring Session - -The steps to integrate with Spring Session are exactly the same as those outline in the link:httpsession.html[HttpSession Guide], so we will skip to running the sample application. - -[[users-sample]] -== users Sample Application - -The users application demonstrates how to allow an application to manage multiple simultaneous browser sessions (i.e. Google Accounts). - -=== Running the users Sample Application - -You can run the sample by obtaining the {download-url}[source code] and invoking the following command: - -[NOTE] -==== -For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379). -Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server. -Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions. -==== - ----- -$ ./gradlew :samples:users:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the users Sample Application - -Try using the application. Authenticate with the following information: - -* **Username** _rob_ -* **Password** _rob_ - -Now click the **Login** button. You should now be authenticated as the user **rob**. - -We can click on links and our user information is preserved. - -* Click on the **Link** link in the navigation bar at the top -* Observe we are still authenticated as **rob** - -Let's add an another account. - -* Return to the *Home* page -* Click on the arrow next to *rob* in the upper right hand corner -* Click **Add Account** - -The log in form is displayed again. Authenticate with the following information: - -* **Username** _luke_ -* **Password** _luke_ - -Now click the **Login** button. You should now be authenticated as the user **luke**. - -We can click on links and our user information is preserved. - -* Click on the **Link** link in the navigation bar at the top -* Observe we are still authenticated as **luke** - -Where did our original user go? Let's switch to our original account. - -* Click on the arrow next to *luke* in the upper right hand corner. -* Click on **Switch Account** -> *rob* - -We are now using the session associated with *rob*. - -== How does it work? - -// tag::how-does-it-work[] - -Let's take a look at how Spring Session keeps track of multiple sessions. - -=== Managing a Single Session - -Spring Session keeps track of the `HttpSession` by adding a value to a cookie named SESSION. -For example, the SESSION cookie might have a value of: - - 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -=== Adding a Session - -We can add another session by requesting a URL that contains a special parameter in it. -By default the parameter name is *_s*. For example, the following URL would create a new session: - -http://localhost:8080/?_s=1 - -NOTE: The parameter value does not indicate the actual session id. -This is important because we never want to allow the session id to be determined by a client to avoid https://www.owasp.org/index.php/Session_fixation[session fixation attacks]. -Additionally, we do not want the session id to be leaked since it is sent as a query parameter. -Remember sensitive information should only be transmitted as a header or in the body of the request. - -Rather than creating the URL ourselves, we can utilize the `HttpSessionManager` to do this for us. -We can obtain the `HttpSessionManager` from the `HttpServletRequest` using the following: - -.src/main/java/sample/UserAccountsFilter.java -[source,java,indent=0] ----- -include::{samples-dir}javaconfig/users/src/main/java/sample/UserAccountsFilter.java[tags=HttpSessionManager] ----- - -We can now use it to create a URL to add another session. - -.src/main/java/sample/UserAccountsFilter.java -[source,java,indent=0] ----- -include::{samples-dir}javaconfig/users/src/main/java/sample/UserAccountsFilter.java[tags=addAccountUrl] ----- - -<1> We have an existing variable named `unauthenticatedAlias`. -The value is an alias that points to an existing unauthenticated session. -If no such session exists, the value is null. -This ensures if we have an existing unauthenticated session that we use it instead of creating a new session. -<2> If all of our sessions are already associated to a user, we create a new session alias. -<3> If there is an existing session that is not associated to a user, we use its session alias. -<4> Finally, we create the add account URL. -The URL contains a session alias that either points to an existing unauthenticated session or is an alias that is unused thus signaling to create a new session associated to that alias. - -Now our SESSION cookie looks something like this: - - 0 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e 1 1d526d4a-c462-45a4-93d9-84a39b6d44ad - -Such that: - -* There is a session with the id *7e8383a4-082c-4ffe-a4bc-c40fd3363c5e* -** The alias for this session is *0*. -For example, if the URL is http://localhost:8080/?_s=0 this alias would be used. -** This is the default session. -This means that if no session alias is specified, then this session is used. -For example, if the URL is http://localhost:8080/ this session would be used. -* There is a session with the id *1d526d4a-c462-45a4-93d9-84a39b6d44ad* -** The alias for this session is *1*. -If the session alias is *1*, then this session is used. -For example, if the URL is http://localhost:8080/?_s=1 this alias would be used. - -=== Automatic Session Alias Inclusion with encodeURL - -The nice thing about specifying the session alias in the URL is that we can have multiple tabs open with different active sessions. -The bad thing is that we need to include the session alias in every URL of our application. -Fortunately, Spring Session will automatically include the session alias in any URL that passes through http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#encodeURL(java.lang.String)[HttpServletResponse#encodeURL(java.lang.String)] - -This means that if you are using standard tag libraries the session alias is automatically included in the URL. -For example, if we are currently using the session with the alias of *1*, then the following: - -.src/main/webapp/index.jsp -[source,xml,indent=0] ----- -include::{samples-dir}javaconfig/users/src/main/webapp/index.jsp[tags=link] ----- - -will output a link of: - -[source,html] ----- -Link ----- - -// end::how-does-it-work[] diff --git a/docs/src/docs/asciidoc/index.adoc b/docs/src/docs/asciidoc/index.adoc index c1911f29..e5509f83 100644 --- a/docs/src/docs/asciidoc/index.adoc +++ b/docs/src/docs/asciidoc/index.adoc @@ -18,7 +18,6 @@ Spring Session provides an API and implementations for managing a user's session * <> - allows replacing the HttpSession in an application container (i.e. Tomcat) neutral way. Additional features include: ** **Clustered Sessions** - Spring Session makes it trivial to support <> without being tied to an application container specific solution. -** **Multiple Browser Sessions** - Spring Session supports <> in a single browser instance (i.e. multiple authenticated accounts similar to Google). ** **RESTful APIs** - Spring Session allows providing session ids in headers to work with <> * <> - provides the ability to keep the `HttpSession` alive when receiving WebSocket messages @@ -98,10 +97,6 @@ If you are looking to get started with Spring Session, the best place to start i | Demonstrates how to use Spring Session in a REST application to support authenticating with a header. | link:guides/java-rest.html[REST Guide] -| {gh-samples-url}javaconfig/users[Multiple Users] -| Demonstrates how to use Spring Session to manage multiple simultaneous browser sessions (i.e Google Accounts). -| link:guides/java-users.html[Multiple Users Guide] - |=== .Sample Applications using Spring XML based configuration @@ -144,7 +139,6 @@ This means that developers can switch the `HttpSession` implementation out with We have already mentioned that Spring Session provides transparent integration with `HttpSession`, but what benefits do we get out of this? * **Clustered Sessions** - Spring Session makes it trivial to support <> without being tied to an application container specific solution. -* **Multiple Browser Sessions** - Spring Session supports <> in a single browser instance (i.e. multiple authenticated accounts similar to Google). * **RESTful APIs** - Spring Session allows providing session ids in headers to work with <> [[httpsession-redis]] @@ -284,17 +278,6 @@ public class SessionRepositoryFilter implements Filter { By passing in a custom `HttpServletRequest` implementation into the `FilterChain` we ensure that anything invoked after our `Filter` uses the custom `HttpSession` implementation. This highlights why it is important that Spring Session's `SessionRepositoryFilter` must be placed before anything that interacts with the `HttpSession`. -[[httpsession-multi]] -=== Multiple HttpSessions in Single Browser - -Spring Session has the ability to support multiple sessions in a single browser instance. -This provides the ability to support authenticating with multiple users in the same browser instance (i.e. Google Accounts). - -NOTE: The <> provides a complete working example of managing multiple users in the same browser instance. -You can follow the basic steps for integration below, but you are encouraged to follow along with the detailed Manage Multiple Users Guide when integrating with your own application. - -include::guides/java-users.adoc[tags=how-does-it-work,leveloffset=+1] - [[httpsession-rest]] === HttpSession & RESTful APIs diff --git a/samples/javaconfig/users/gradle/dependency-management.gradle b/samples/javaconfig/users/gradle/dependency-management.gradle deleted file mode 100644 index 044391f3..00000000 --- a/samples/javaconfig/users/gradle/dependency-management.gradle +++ /dev/null @@ -1,5 +0,0 @@ -dependencyManagement { - dependencies { - dependency 'org.webjars:bootstrap:3.3.6' - } -} diff --git a/samples/javaconfig/users/spring-session-sample-javaconfig-users.gradle b/samples/javaconfig/users/spring-session-sample-javaconfig-users.gradle deleted file mode 100644 index 46d6c4f9..00000000 --- a/samples/javaconfig/users/spring-session-sample-javaconfig-users.gradle +++ /dev/null @@ -1,24 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile project(':spring-session-data-redis') - compile "org.springframework:spring-web" - compile "io.lettuce:lettuce-core" - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies - compile "org.testcontainers:testcontainers" - - providedCompile "javax.servlet:javax.servlet-api" - - testCompile "junit:junit" - testCompile "org.springframework:spring-test" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies -} - -gretty { - jvmArgs = ['-Dspring.profiles.active=embedded-redis'] -} diff --git a/samples/javaconfig/users/src/integration-test/java/sample/UserTests.java b/samples/javaconfig/users/src/integration-test/java/sample/UserTests.java deleted file mode 100644 index c3f2ae2c..00000000 --- a/samples/javaconfig/users/src/integration-test/java/sample/UserTests.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2014-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 sample; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import sample.pages.HomePage; -import sample.pages.LinkPage; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Pool Dolorier - */ -public class UserTests { - - private static final String ROB = "rob"; - private static final String USERNAME = "username"; - private static final String LUKE = "luke"; - private static final String NAV_LINK = "navLink"; - private static final String HREF = "href"; - private static final String ADD_ACCOUNT = "addAccount"; - private static final String UN = "un"; - private static final String LOGOUT = "logout"; - private static final String ERROR = "error"; - - private WebDriver driver; - - @Before - public void setup() { - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void firstVisitNotAuthenticated() { - HomePage homePage = HomePage.go(this.driver); - homePage.assertAt(); - homePage.assertUserNameEmpty(); - } - - @Test - public void invalidLogin() { - HomePage homePage = HomePage.go(this.driver); - String user = ROB; - homePage.login(user, user + "invalid"); - WebElement errorMessage = homePage.getElementById(ERROR); - homePage.assertAt(); - homePage.assertErrorInvalidAuthentication(errorMessage); - } - - @Test - public void emptyUsername() { - HomePage homePage = HomePage.go(this.driver); - homePage.login("", ""); - WebElement errorMessage = homePage.getElementById(ERROR); - homePage.assertAt(); - homePage.assertErrorInvalidAuthentication(errorMessage); - } - - @Test - public void loginSingleUser() { - loginRob(); - } - - @Test - public void addAccount() { - backHomeForAddLukeAccount(); - } - - @Test - public void logInSecondUser() { - logInLukeAccount(); - } - - @Test - public void followingLinksKeepsNewSession() { - followingLukeLinkSession(); - - } - - @Test - public void switchAccountRob() { - switchAccountRobHomePage(); - } - - @Test - public void followingLinksKeepsOriginalSession() { - followingRobLinkSession(); - } - - @Test - public void switchAccountLuke() { - switchAccountLukeHomePage(); - } - - @Test - public void logoutLuke() { - logoutLukeAccount(); - } - - @Test - public void switchBackRob() { - switchBackRobHomePage(); - } - - @Test - public void logoutRob() { - logoutRobAccount(); - } - - private HomePage loginRob() { - HomePage home = HomePage.go(this.driver); - - String user = ROB; - home.login(user, user); - WebElement username = home.getElementById(UN); - assertThat(username.getText()).isEqualTo(user); - return home; - } - - private HomePage backHomeForAddLukeAccount() { - HomePage robHome = loginRob(); - - String addAccountLink = robHome.getContentAttributeByElementId(ADD_ACCOUNT, HREF); - HomePage backHome = robHome.home(this.driver, addAccountLink); - WebElement username = backHome.getElementById(USERNAME); - assertThat(username.getText()).isEmpty(); - return backHome; - } - - private HomePage logInLukeAccount() { - HomePage home = backHomeForAddLukeAccount(); - - String secondUser = LUKE; - home.login(secondUser, secondUser); - WebElement secondUserName = home.getElementById(UN); - assertThat(secondUserName.getText()).isEqualTo(secondUser); - return home; - } - - private LinkPage followingLukeLinkSession() { - HomePage lukeHome = logInLukeAccount(); - - String navLink = lukeHome.getContentAttributeByElementId(NAV_LINK, HREF); - LinkPage lukeLinkPage = lukeHome.linkPage(this.driver, navLink); - lukeLinkPage.assertAt(); - WebElement username = lukeLinkPage.getElementById(UN); - assertThat(username.getText()).isEqualTo(LUKE); - return lukeLinkPage; - } - - private HomePage switchAccountRobHomePage() { - LinkPage lukeLinkPage = followingLukeLinkSession(); - - String robSwitch = lukeLinkPage.getSwitchElementId(ROB); - String switchLink = lukeLinkPage.getContentAttributeByElementId(robSwitch, HREF); - HomePage robHome = lukeLinkPage.home(this.driver, switchLink); - WebElement username = robHome.getElementById(UN); - assertThat(username.getText()).isEqualTo(ROB); - return robHome; - } - - private LinkPage followingRobLinkSession() { - HomePage robHome = switchAccountRobHomePage(); - - String navLink = robHome.getContentAttributeByElementId(NAV_LINK, HREF); - LinkPage robLinkPage = robHome.linkPage(this.driver, navLink); - robLinkPage.assertAt(); - WebElement username = robLinkPage.getElementById(UN); - assertThat(username.getText()).isEqualTo(ROB); - return robLinkPage; - } - - private HomePage switchAccountLukeHomePage() { - LinkPage robLinkPage = followingRobLinkSession(); - - String lukeSwitch = robLinkPage.getSwitchElementId(LUKE); - String lukeSwitchLink = robLinkPage.getContentAttributeByElementId(lukeSwitch, HREF); - HomePage lukeHome = robLinkPage.home(this.driver, lukeSwitchLink); - WebElement username = lukeHome.getElementById(UN); - assertThat(username.getText()).isEqualTo(LUKE); - return lukeHome; - } - - private HomePage logoutLukeAccount() { - HomePage lukeHome = switchAccountLukeHomePage(); - - String logoutLink = lukeHome.getContentAttributeByElementId(LOGOUT, HREF); - HomePage home = lukeHome.home(this.driver, logoutLink); - home.assertUserNameEmpty(); - return home; - } - - private HomePage switchBackRobHomePage() { - HomePage homePage = logoutLukeAccount(); - - String robSwitch = homePage.getSwitchElementId(ROB); - String robSwitchLink = homePage.getContentAttributeByElementId(robSwitch, HREF); - HomePage robHome = homePage.home(this.driver, robSwitchLink); - WebElement username = robHome.getElementById(UN); - assertThat(username.getText()).isEqualTo(ROB); - return robHome; - } - - private HomePage logoutRobAccount() { - HomePage robHome = switchBackRobHomePage(); - - String logoutLink = robHome.getContentAttributeByElementId(LOGOUT, HREF); - HomePage home = robHome.home(this.driver, logoutLink); - home.assertUserNameEmpty(); - return home; - } -} diff --git a/samples/javaconfig/users/src/integration-test/java/sample/pages/BasePage.java b/samples/javaconfig/users/src/integration-test/java/sample/pages/BasePage.java deleted file mode 100644 index 8a6b6b94..00000000 --- a/samples/javaconfig/users/src/integration-test/java/sample/pages/BasePage.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2014-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 sample.pages; - -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.PageFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Pool Dolorier - */ -public abstract class BasePage { - - private WebDriver driver; - - public BasePage(WebDriver driver) { - this.driver = driver; - } - - public WebDriver getDriver() { - return this.driver; - } - - public static void get(WebDriver driver, String get) { - String baseUrl = "http://localhost:" + System.getProperty("app.port"); - driver.get(baseUrl + get); - } - - public static void getFrom(WebDriver driver, String resourceUrl) { - driver.get(resourceUrl); - } - - public HomePage home(WebDriver driver, String resourceUrl) { - getFrom(driver, resourceUrl); - return PageFactory.initElements(driver, HomePage.class); - } - - public LinkPage linkPage(WebDriver driver, String resourceUrl) { - getFrom(driver, resourceUrl); - return PageFactory.initElements(driver, LinkPage.class); - } - - public String getSwitchElementId(String user) { - return "switchAccount" + user; - } - - public WebElement getElementById(String id) { - return this.driver.findElement(By.id(id)); - } - - public String getContentAttributeByElementId(String id, String attribute) { - WebElement element = getElementById(id); - assertThat(element.getAttribute(attribute)).isNotEmpty(); - return element.getAttribute(attribute); - } - -} diff --git a/samples/javaconfig/users/src/integration-test/java/sample/pages/HomePage.java b/samples/javaconfig/users/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index a994bddd..00000000 --- a/samples/javaconfig/users/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2014-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 sample.pages; - -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Pool Dolorier - */ -public class HomePage extends BasePage { - - @FindBy(name = "username") - private WebElement username; - - @FindBy(name = "password") - private WebElement password; - - @FindBy(css = "form[method='post']") - private WebElement form; - - public HomePage(WebDriver driver) { - super(driver); - } - - public static HomePage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, HomePage.class); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Demonstrates Multi User Log In"); - } - - public void assertUserNameEmpty() { - assertThat(this.username.getText()).isEmpty(); - } - - public void assertErrorInvalidAuthentication(WebElement errorMessage) { - assertThat(errorMessage.getText()).isEqualTo("Invalid username / password. Please ensure the username is the same as the password."); - } - - public void login(String user, String password) { - this.username.sendKeys(user); - this.password.sendKeys(password); - this.form.submit(); - } -} diff --git a/samples/javaconfig/users/src/integration-test/java/sample/pages/LinkPage.java b/samples/javaconfig/users/src/integration-test/java/sample/pages/LinkPage.java deleted file mode 100644 index 1d27240f..00000000 --- a/samples/javaconfig/users/src/integration-test/java/sample/pages/LinkPage.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2014-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 sample.pages; - -import org.openqa.selenium.WebDriver; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Pool Dolorier - */ -public class LinkPage extends BasePage { - - public LinkPage(WebDriver driver) { - super(driver); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Linked Page"); - } -} diff --git a/samples/javaconfig/users/src/main/java/sample/Account.java b/samples/javaconfig/users/src/main/java/sample/Account.java deleted file mode 100644 index e09d75f6..00000000 --- a/samples/javaconfig/users/src/main/java/sample/Account.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2014-2016 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 sample; - -public class Account { - private String username; - - private String logoutUrl; - - private String switchAccountUrl; - - public Account(String username, String logoutUrl, String switchAccountUrl) { - super(); - this.username = username; - this.logoutUrl = logoutUrl; - this.switchAccountUrl = switchAccountUrl; - } - - public String getUsername() { - return this.username; - } - - public String getLogoutUrl() { - return this.logoutUrl; - } - - public String getSwitchAccountUrl() { - return this.switchAccountUrl; - } - -} diff --git a/samples/javaconfig/users/src/main/java/sample/Config.java b/samples/javaconfig/users/src/main/java/sample/Config.java deleted file mode 100644 index 6fc53cdd..00000000 --- a/samples/javaconfig/users/src/main/java/sample/Config.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 sample; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; - -/** - * @author Rob Winch - */ -@Import(EmbeddedRedisConfig.class) -// tag::class[] -@Configuration -@EnableRedisHttpSession -public class Config { - - @Bean - public LettuceConnectionFactory connectionFactory() { - return new LettuceConnectionFactory(); - } -} -// end::class[] diff --git a/samples/javaconfig/users/src/main/java/sample/EmbeddedRedisConfig.java b/samples/javaconfig/users/src/main/java/sample/EmbeddedRedisConfig.java deleted file mode 100644 index 5e5265cc..00000000 --- a/samples/javaconfig/users/src/main/java/sample/EmbeddedRedisConfig.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2014-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 sample; - -import java.io.IOException; - -import org.testcontainers.containers.GenericContainer; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.context.annotation.Profile; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; - -@Configuration -@Profile("embedded-redis") -public class EmbeddedRedisConfig { - - private static final String REDIS_DOCKER_IMAGE = "redis:4.0.2"; - - @Bean(initMethod = "start") - public GenericContainer redisContainer() { - return new GenericContainer(REDIS_DOCKER_IMAGE) { - - @Override - public void close() { - super.close(); - try { - this.dockerClient.close(); - } - catch (IOException ignored) { - } - } - - }.withExposedPorts(6379); - } - - @Bean - @Primary - public LettuceConnectionFactory redisConnectionFactory() { - return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(), - redisContainer().getFirstMappedPort()); - } - -} diff --git a/samples/javaconfig/users/src/main/java/sample/Initializer.java b/samples/javaconfig/users/src/main/java/sample/Initializer.java deleted file mode 100644 index e1ce9694..00000000 --- a/samples/javaconfig/users/src/main/java/sample/Initializer.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014-2016 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 sample; - -import javax.servlet.ServletContext; - -import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; - -/** - * @author Rob Winch - */ -public class Initializer extends AbstractHttpSessionApplicationInitializer { - - public Initializer() { - super(Config.class); - } - - @Override - protected void afterSessionRepositoryFilter(ServletContext servletContext) { - appendFilters(servletContext, new UserAccountsFilter()); - } -} diff --git a/samples/javaconfig/users/src/main/java/sample/LoginServlet.java b/samples/javaconfig/users/src/main/java/sample/LoginServlet.java deleted file mode 100644 index 59e0837f..00000000 --- a/samples/javaconfig/users/src/main/java/sample/LoginServlet.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2014-2016 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 sample; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/login") -public class LoginServlet extends HttpServlet { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String username = req.getParameter("username"); - String password = req.getParameter("password"); - - if (username != null && !"".equals(username) && username.equals(password)) { - req.getSession().setAttribute("username", username); - String url = resp.encodeRedirectURL(req.getContextPath() + "/"); - resp.sendRedirect(url); - } - else { - String url = resp.encodeRedirectURL(req.getContextPath() + "/?error"); - resp.sendRedirect(url); - } - } - - private static final long serialVersionUID = -8157634860354132501L; -} diff --git a/samples/javaconfig/users/src/main/java/sample/LogoutServlet.java b/samples/javaconfig/users/src/main/java/sample/LogoutServlet.java deleted file mode 100644 index f17ee20a..00000000 --- a/samples/javaconfig/users/src/main/java/sample/LogoutServlet.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014-2016 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 sample; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -@WebServlet("/logout") -public class LogoutServlet extends HttpServlet { - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - HttpSession session = req.getSession(false); - if (session != null) { - session.invalidate(); - } - String url = resp.encodeRedirectURL(req.getContextPath() + "/"); - resp.sendRedirect(url); - } - - private static final long serialVersionUID = 4061762524521437433L; -} diff --git a/samples/javaconfig/users/src/main/java/sample/UserAccountsFilter.java b/samples/javaconfig/users/src/main/java/sample/UserAccountsFilter.java deleted file mode 100644 index 2781e248..00000000 --- a/samples/javaconfig/users/src/main/java/sample/UserAccountsFilter.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2014-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 sample; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -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.HttpServletRequest; - -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; -import org.springframework.session.web.http.HttpSessionManager; - -public class UserAccountsFilter implements Filter { - - public void init(FilterConfig filterConfig) throws ServletException { - } - - @SuppressWarnings("unchecked") - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException { - HttpServletRequest httpRequest = (HttpServletRequest) request; - - // tag::HttpSessionManager[] - HttpSessionManager sessionManager = (HttpSessionManager) httpRequest - .getAttribute(HttpSessionManager.class.getName()); - // end::HttpSessionManager[] - SessionRepository repo = (SessionRepository) httpRequest - .getAttribute(SessionRepository.class.getName()); - - String currentSessionAlias = sessionManager.getCurrentSessionAlias(httpRequest); - Map sessionIds = sessionManager.getSessionIds(httpRequest); - String unauthenticatedAlias = null; - - String contextPath = httpRequest.getContextPath(); - List accounts = new ArrayList<>(); - Account currentAccount = null; - for (Map.Entry entry : sessionIds.entrySet()) { - String alias = entry.getKey(); - String sessionId = entry.getValue(); - - Session session = repo.findById(sessionId); - if (session == null) { - continue; - } - - String username = session.getAttribute("username"); - if (username == null) { - unauthenticatedAlias = alias; - continue; - } - - String logoutUrl = sessionManager.encodeURL("./logout", alias); - String switchAccountUrl = sessionManager.encodeURL("./", alias); - Account account = new Account(username, logoutUrl, switchAccountUrl); - if (currentSessionAlias.equals(alias)) { - currentAccount = account; - } - else { - accounts.add(account); - } - } - - // tag::addAccountUrl[] - String addAlias = unauthenticatedAlias == null ? // <1> - sessionManager.getNewSessionAlias(httpRequest) - : // <2> - unauthenticatedAlias; // <3> - String addAccountUrl = sessionManager.encodeURL(contextPath, addAlias); // <4> - // end::addAccountUrl[] - - httpRequest.setAttribute("currentAccount", currentAccount); - httpRequest.setAttribute("addAccountUrl", addAccountUrl); - httpRequest.setAttribute("accounts", accounts); - - chain.doFilter(request, response); - } - - public void destroy() { - } - -} diff --git a/samples/javaconfig/users/src/main/resources/logback.xml b/samples/javaconfig/users/src/main/resources/logback.xml deleted file mode 100644 index 20e90221..00000000 --- a/samples/javaconfig/users/src/main/resources/logback.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - diff --git a/samples/javaconfig/users/src/main/webapp/META-INF/MANIFEST.MF b/samples/javaconfig/users/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29b..00000000 diff --git a/samples/javaconfig/users/src/main/webapp/assets/js/ie10-viewport-bug-workaround.js b/samples/javaconfig/users/src/main/webapp/assets/js/ie10-viewport-bug-workaround.js deleted file mode 100644 index b5765360..00000000 --- a/samples/javaconfig/users/src/main/webapp/assets/js/ie10-viewport-bug-workaround.js +++ /dev/null @@ -1,22 +0,0 @@ -/*! - * IE10 viewport hack for Surface/desktop Windows 8 bug - * Copyright 2014 Twitter, Inc. - * Licensed under the Creative Commons Attribution 3.0 Unported License. For - * details, see http://creativecommons.org/licenses/by/3.0/. - */ - -// See the Getting Started docs for more information: -// http://getbootstrap.com/getting-started/#support-ie10-width - -(function () { - 'use strict'; - if (navigator.userAgent.match(/IEMobile\/10\.0/)) { - var msViewportStyle = document.createElement('style') - msViewportStyle.appendChild( - document.createTextNode( - '@-ms-viewport{width:auto!important}' - ) - ) - document.querySelector('head').appendChild(msViewportStyle) - } -})(); \ No newline at end of file diff --git a/samples/javaconfig/users/src/main/webapp/index.jsp b/samples/javaconfig/users/src/main/webapp/index.jsp deleted file mode 100644 index 657d2a5a..00000000 --- a/samples/javaconfig/users/src/main/webapp/index.jsp +++ /dev/null @@ -1,112 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Demonstrates Multi User Log In - - "> - - - -
- - - -

Description

-

This application demonstrates how to use Spring Session to authenticate as multiple users at a time. View authenticated users in the upper right corner.

- - - -

Please Log In

-

You are not currently authenticated with this session. You can authenticate with any username password combination that are equal. A few examples to try:

-
    -
  • Username rob and Password rob
  • -
  • Username luke and Password luke
  • -
- -
Invalid username / password. Please ensure the username is the same as the password.
-
- -
-
- - -
-
- - -
- -
-
- -

-

You are authenticated as . Observe that you can navigate links and the correct session is used. Using the links in the upper right corner you can:

-
    -
  • Log Out
  • -
  • Switch Accounts
  • -
  • Add Account
  • -
-
-
-
- - - - - - - - - - diff --git a/samples/javaconfig/users/src/main/webapp/link.jsp b/samples/javaconfig/users/src/main/webapp/link.jsp deleted file mode 100644 index ecf69270..00000000 --- a/samples/javaconfig/users/src/main/webapp/link.jsp +++ /dev/null @@ -1,85 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Linked Page - - "> - - - -
- - - -

Description

-

This page demonstrates how we keep track of the correct user session between links even when multiple tabs are open. Try opening another tab with a different user and browse. Then come back to the original tab and see the correct user is maintained.

- - - -

Please Log In

-

You are not currently authenticated with this session. Log In

-
- -

-

You are authenticated as . Observe that you can navigate links and the correct session is used. Using the links in the upper right corner you can:

-
    -
  • Log Out
  • -
  • Switch Accounts
  • -
  • Add Account
  • -
-
-
-
- - - - - - - - - - diff --git a/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java b/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java index 65df4784..373a1a93 100644 --- a/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java +++ b/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java @@ -42,7 +42,6 @@ import org.springframework.session.web.http.CookieHttpSessionStrategy; import org.springframework.session.web.http.CookieSerializer; import org.springframework.session.web.http.DefaultCookieSerializer; import org.springframework.session.web.http.HttpSessionStrategy; -import org.springframework.session.web.http.MultiHttpSessionStrategy; import org.springframework.session.web.http.SessionEventHttpSessionListenerAdapter; import org.springframework.session.web.http.SessionRepositoryFilter; import org.springframework.util.ClassUtils; @@ -127,16 +126,11 @@ public class SpringHttpSessionConfiguration implements ApplicationContextAware { SessionRepositoryFilter sessionRepositoryFilter = new SessionRepositoryFilter<>( sessionRepository); sessionRepositoryFilter.setServletContext(this.servletContext); - if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) { - sessionRepositoryFilter.setHttpSessionStrategy( - (MultiHttpSessionStrategy) this.httpSessionStrategy); - } - else { - sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy); - } + sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy); return sessionRepositoryFilter; } + @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (ClassUtils.isPresent( diff --git a/spring-session-core/src/main/java/org/springframework/session/web/http/CookieHttpSessionStrategy.java b/spring-session-core/src/main/java/org/springframework/session/web/http/CookieHttpSessionStrategy.java index 61c5e465..a0ee72fa 100644 --- a/spring-session-core/src/main/java/org/springframework/session/web/http/CookieHttpSessionStrategy.java +++ b/spring-session-core/src/main/java/org/springframework/session/web/http/CookieHttpSessionStrategy.java @@ -16,20 +16,10 @@ package org.springframework.session.web.http; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; import org.springframework.session.Session; import org.springframework.session.web.http.CookieSerializer.CookieValue; @@ -68,222 +58,38 @@ import org.springframework.session.web.http.CookieSerializer.CookieValue; * Set-Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6; Expires=Thur, 1 Jan 1970 00:00:00 GMT; Secure; HttpOnly * * - *

Supporting Multiple Simultaneous Sessions

- * - *

- * By default multiple sessions are also supported. Once a session is established with the - * browser, another session can be initiated by specifying a unique value for the - * {@link #setSessionAliasParamName(String)}. For example, a request to: - *

- * - *
- * GET /messages/?_s=1416195761178 HTTP/1.1
- * Host: example.com
- * Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6
- * 
- * - * Will result in the following response: - * - *
- *  HTTP/1.1 200 OK
- * Set-Cookie: SESSION="0 f81d4fae-7dec-11d0-a765-00a0c91e6bf6 1416195761178 8a929cde-2218-4557-8d4e-82a79a37876d"; Expires=Thur, 1 Jan 1970 00:00:00 GMT; Secure; HttpOnly
- * 
- * - *

- * To use the original session a request without the HTTP parameter u can be made. To use - * the new session, a request with the HTTP parameter _s=1416195761178 can be used. By - * default URLs will be rewritten to include the currently selected session. - *

- * - *

Selecting Sessions

- * - *

- * Sessions can be managed by using the HttpSessionManager and SessionRepository. If you - * are not using Spring in the rest of your application you can obtain a reference from - * the HttpServletRequest attributes. An example is provided below: - *

- * - * - * HttpSessionManager sessionManager = - * (HttpSessionManager) req.getAttribute(HttpSessionManager.class.getName()); - * SessionRepository<Session> repo = - * (SessionRepository<Session>) req.getAttribute(SessionRepository.class.getName()); - * - * String currentSessionAlias = sessionManager.getCurrentSessionAlias(req); - * Map<String, String> sessionIds = sessionManager.getSessionIds(req); - * String newSessionAlias = String.valueOf(System.currentTimeMillis()); - * - * String contextPath = req.getContextPath(); - * List<Account> accounts = new ArrayList<>(); - * Account currentAccount = null; for(Map.Entry<String, String> entry : - * sessionIds.entrySet()) { String alias = entry.getKey(); String sessionId = - * entry.getValue(); - * - * - * Session session = repo.findById(sessionId); if(session == null) { continue; } - * - * String username = session.getAttribute("username"); if(username == null) { - * newSessionAlias = alias; continue; } - * - * String logoutUrl = sessionManager.encodeURL("./logout", alias); String switchAccountUrl - * = sessionManager.encodeURL("./", alias); Account account = new Account(username, - * logoutUrl, switchAccountUrl); if(currentSessionAlias.equals(alias)) { currentAccount = - * account; } else { accounts.add(account); } } - * - * req.setAttribute("currentAccount", currentAccount); req.setAttribute("addAccountUrl", - * sessionManager.encodeURL(contextPath, newSessionAlias)); req.setAttribute("accounts", - * accounts); } - * - * * @author Rob Winch + * @author Vedran Pavic * @since 1.0 */ -public final class CookieHttpSessionStrategy - implements MultiHttpSessionStrategy, HttpSessionManager { - /** - * The default delimiter for both serialization and deserialization. - */ - private static final String DEFAULT_DELIMITER = " "; +public final class CookieHttpSessionStrategy implements HttpSessionStrategy { - private static final String SESSION_IDS_WRITTEN_ATTR = CookieHttpSessionStrategy.class - .getName().concat(".SESSIONS_WRITTEN_ATTR"); - - static final String DEFAULT_ALIAS = "0"; - - static final String DEFAULT_SESSION_ALIAS_PARAM_NAME = "_s"; - - private static final Pattern ALIAS_PATTERN = Pattern.compile("^[\\w-]{1,50}$"); - - private String sessionParam = DEFAULT_SESSION_ALIAS_PARAM_NAME; + private static final String WRITTEN_SESSION_ID_ATTR = CookieHttpSessionStrategy.class + .getName().concat(".WRITTEN_SESSION_ID_ATTR"); private CookieSerializer cookieSerializer = new DefaultCookieSerializer(); - /** - * The delimiter between a session alias and a session id when reading a cookie value. - * The default value is " ". - */ - private String deserializationDelimiter = DEFAULT_DELIMITER; - - /** - * The delimiter between a session alias and a session id when writing a cookie value. - * The default is " ". - */ - private String serializationDelimiter = DEFAULT_DELIMITER; - - public String getRequestedSessionId(HttpServletRequest request) { - Map sessionIds = getSessionIds(request); - String sessionAlias = getCurrentSessionAlias(request); - return sessionIds.get(sessionAlias); - } - - public String getCurrentSessionAlias(HttpServletRequest request) { - if (this.sessionParam == null) { - return DEFAULT_ALIAS; - } - String u = request.getParameter(this.sessionParam); - if (u == null) { - return DEFAULT_ALIAS; - } - if (!ALIAS_PATTERN.matcher(u).matches()) { - return DEFAULT_ALIAS; - } - return u; - } - - public String getNewSessionAlias(HttpServletRequest request) { - Set sessionAliases = getSessionIds(request).keySet(); - if (sessionAliases.isEmpty()) { - return DEFAULT_ALIAS; - } - long lastAlias = Long.decode(DEFAULT_ALIAS); - for (String alias : sessionAliases) { - long selectedAlias = safeParse(alias); - if (selectedAlias > lastAlias) { - lastAlias = selectedAlias; - } - } - return Long.toHexString(lastAlias + 1); - } - - private long safeParse(String hex) { - try { - return Long.decode("0x" + hex); - } - catch (NumberFormatException notNumber) { - return 0; - } + @Override + public List getRequestedSessionIds(HttpServletRequest request) { + return this.cookieSerializer.readCookieValues(request); } + @Override public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) { - Set sessionIdsWritten = getSessionIdsWritten(request); - if (sessionIdsWritten.contains(session.getId())) { + String sessionId = session.getId(); + if (sessionId.equals(request.getAttribute(WRITTEN_SESSION_ID_ATTR))) { return; } - sessionIdsWritten.add(session.getId()); - - Map sessionIds = getSessionIds(request); - String sessionAlias = getCurrentSessionAlias(request); - sessionIds.put(sessionAlias, session.getId()); - - String cookieValue = createSessionCookieValue(sessionIds); + request.setAttribute(WRITTEN_SESSION_ID_ATTR, sessionId); this.cookieSerializer - .writeCookieValue(new CookieValue(request, response, cookieValue)); - } - - @SuppressWarnings("unchecked") - private Set getSessionIdsWritten(HttpServletRequest request) { - Set sessionsWritten = (Set) request - .getAttribute(SESSION_IDS_WRITTEN_ATTR); - if (sessionsWritten == null) { - sessionsWritten = new HashSet<>(); - request.setAttribute(SESSION_IDS_WRITTEN_ATTR, sessionsWritten); - } - return sessionsWritten; - } - - private String createSessionCookieValue(Map sessionIds) { - if (sessionIds.isEmpty()) { - return ""; - } - if (sessionIds.size() == 1 && sessionIds.keySet().contains(DEFAULT_ALIAS)) { - return sessionIds.values().iterator().next(); - } - - StringBuilder sb = new StringBuilder(); - for (Map.Entry entry : sessionIds.entrySet()) { - String alias = entry.getKey(); - String id = entry.getValue(); - - sb.append(alias); - sb.append(this.serializationDelimiter); - sb.append(id); - sb.append(this.serializationDelimiter); - } - sb.deleteCharAt(sb.length() - 1); - return sb.toString(); + .writeCookieValue(new CookieValue(request, response, sessionId)); } + @Override public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) { - Map sessionIds = getSessionIds(request); - String requestedAlias = getCurrentSessionAlias(request); - sessionIds.remove(requestedAlias); - - String cookieValue = createSessionCookieValue(sessionIds); - this.cookieSerializer - .writeCookieValue(new CookieValue(request, response, cookieValue)); - } - - /** - * Sets the name of the HTTP parameter that is used to specify the session alias. If - * the value is null, then only a single session is supported per browser. - * - * @param sessionAliasParamName the name of the HTTP parameter used to specify the - * session alias. If null, then ony a single session is supported per browser. - */ - public void setSessionAliasParamName(String sessionAliasParamName) { - this.sessionParam = sessionAliasParamName; + this.cookieSerializer.writeCookieValue(new CookieValue(request, response, "")); } /** @@ -298,151 +104,4 @@ public final class CookieHttpSessionStrategy this.cookieSerializer = cookieSerializer; } - /** - * Sets the delimiter between a session alias and a session id when deserializing a - * cookie. The default is " " This is useful when using - * RFC 6265 for writing the cookies - * which doesn't allow for spaces in the cookie values. - * - * @param delimiter the delimiter to set (i.e. "_ " will try a delimeter of either "_" - * or " ") - */ - public void setDeserializationDelimiter(String delimiter) { - this.deserializationDelimiter = delimiter; - } - - /** - * Sets the delimiter between a session alias and a session id when deserializing a - * cookie. The default is " ". This is useful when using - * RFC 6265 for writing the cookies - * which doesn't allow for spaces in the cookie values. - * - * @param delimiter the delimiter to set (i.e. "_") - */ - public void setSerializationDelimiter(String delimiter) { - this.serializationDelimiter = delimiter; - } - - public Map getSessionIds(HttpServletRequest request) { - List cookieValues = this.cookieSerializer.readCookieValues(request); - String sessionCookieValue = cookieValues.isEmpty() ? "" - : cookieValues.iterator().next(); - Map result = new LinkedHashMap<>(); - StringTokenizer tokens = new StringTokenizer(sessionCookieValue, - this.deserializationDelimiter); - if (tokens.countTokens() == 1) { - result.put(DEFAULT_ALIAS, tokens.nextToken()); - return result; - } - while (tokens.hasMoreTokens()) { - String alias = tokens.nextToken(); - if (!tokens.hasMoreTokens()) { - break; - } - String id = tokens.nextToken(); - result.put(alias, id); - } - return result; - } - - public HttpServletRequest wrapRequest(HttpServletRequest request, - HttpServletResponse response) { - request.setAttribute(HttpSessionManager.class.getName(), this); - return request; - } - - public HttpServletResponse wrapResponse(HttpServletRequest request, - HttpServletResponse response) { - return new MultiSessionHttpServletResponse(response, request); - } - - public String encodeURL(String url, String sessionAlias) { - String encodedSessionAlias = urlEncode(sessionAlias); - int queryStart = url.indexOf("?"); - boolean isDefaultAlias = DEFAULT_ALIAS.equals(encodedSessionAlias); - if (queryStart < 0) { - return isDefaultAlias ? url - : url + "?" + this.sessionParam + "=" + encodedSessionAlias; - } - String path = url.substring(0, queryStart); - String query = url.substring(queryStart + 1, url.length()); - String replacement = isDefaultAlias ? "" : "$1" + encodedSessionAlias; - query = query.replaceFirst("((^|&)" + this.sessionParam + "=)([^&]+)?", - replacement); - String sessionParamReplacement = String.format("%s=%s", this.sessionParam, - encodedSessionAlias); - - if (!isDefaultAlias && !query.contains(sessionParamReplacement) - && url.endsWith(query)) { - // no existing alias - if (!(query.endsWith("&") || query.length() == 0)) { - query += "&"; - } - query += sessionParamReplacement; - } - - return path + "?" + query; - } - - private String urlEncode(String value) { - try { - return URLEncoder.encode(value, "UTF-8"); - } - catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - /** - * A {@link CookieHttpSessionStrategy} aware {@link HttpServletResponseWrapper}. - */ - class MultiSessionHttpServletResponse extends HttpServletResponseWrapper { - private final HttpServletRequest request; - - MultiSessionHttpServletResponse(HttpServletResponse response, - HttpServletRequest request) { - super(response); - this.request = request; - } - - private String getCurrentSessionAliasFromUrl(String url) { - String currentSessionAliasFromUrl = null; - int queryStart = url.indexOf("?"); - - if (queryStart >= 0) { - String query = url.substring(queryStart + 1); - Matcher matcher = Pattern - .compile(String.format("%s=([^&]+)", - CookieHttpSessionStrategy.this.sessionParam)) - .matcher(query); - - if (matcher.find()) { - currentSessionAliasFromUrl = matcher.group(1); - } - } - - return currentSessionAliasFromUrl; - } - - @Override - public String encodeRedirectURL(String url) { - String encodedUrl = super.encodeRedirectURL(url); - String currentSessionAliasFromUrl = getCurrentSessionAliasFromUrl(encodedUrl); - String alias = (currentSessionAliasFromUrl != null) - ? currentSessionAliasFromUrl : getCurrentSessionAlias(this.request); - - return CookieHttpSessionStrategy.this.encodeURL(encodedUrl, alias); - } - - @Override - public String encodeURL(String url) { - String encodedUrl = super.encodeURL(url); - String currentSessionAliasFromUrl = getCurrentSessionAliasFromUrl(encodedUrl); - String alias = (currentSessionAliasFromUrl != null) - ? currentSessionAliasFromUrl : getCurrentSessionAlias(this.request); - - return CookieHttpSessionStrategy.this.encodeURL(encodedUrl, alias); - } - } - } diff --git a/spring-session-core/src/main/java/org/springframework/session/web/http/HeaderHttpSessionStrategy.java b/spring-session-core/src/main/java/org/springframework/session/web/http/HeaderHttpSessionStrategy.java index f8534024..50c7a47c 100644 --- a/spring-session-core/src/main/java/org/springframework/session/web/http/HeaderHttpSessionStrategy.java +++ b/spring-session-core/src/main/java/org/springframework/session/web/http/HeaderHttpSessionStrategy.java @@ -16,6 +16,9 @@ package org.springframework.session.web.http; +import java.util.Collections; +import java.util.List; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -52,21 +55,27 @@ import org.springframework.session.Session; * * * @author Rob Winch + * @author Vedran Pavic * @since 1.0 */ public class HeaderHttpSessionStrategy implements HttpSessionStrategy { private String headerName = "X-Auth-Token"; - public String getRequestedSessionId(HttpServletRequest request) { - return request.getHeader(this.headerName); + @Override + public List getRequestedSessionIds(HttpServletRequest request) { + String headerValue = request.getHeader(this.headerName); + return headerValue != null ? Collections.singletonList(headerValue) + : Collections.emptyList(); } + @Override public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) { response.setHeader(this.headerName, session.getId()); } + @Override public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) { response.setHeader(this.headerName, ""); diff --git a/spring-session-core/src/main/java/org/springframework/session/web/http/HttpSessionManager.java b/spring-session-core/src/main/java/org/springframework/session/web/http/HttpSessionManager.java deleted file mode 100644 index 6f061a03..00000000 --- a/spring-session-core/src/main/java/org/springframework/session/web/http/HttpSessionManager.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2014-2016 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.Map; - -import javax.servlet.http.HttpServletRequest; - -/** - * Allows managing a mapping of alias to the session id for having multiple active - * sessions at the same time. - * - * @author Rob Winch - * @since 1.0 - * - */ -public interface HttpSessionManager { - - /** - * Gets the current session's alias from the {@link HttpServletRequest}. - * - * @param request the {@link HttpServletRequest} to obtain the current session's alias - * from. - * @return the current sessions' alias. Cannot be null. - */ - String getCurrentSessionAlias(HttpServletRequest request); - - /** - * Gets a mapping of the session alias to the session id from the - * {@link HttpServletRequest}. - * - * @param request the {@link HttpServletRequest} to obtain the mapping from. Cannot be - * null. - * @return a mapping of the session alias to the session id from the - * {@link HttpServletRequest}. Cannot be null. - */ - Map getSessionIds(HttpServletRequest request); - - /** - * Provides the ability to encode the URL for a given session alias. - * - * @param url the url to encode. - * @param sessionAlias the session alias to encode. - * @return the encoded URL - */ - String encodeURL(String url, String sessionAlias); - - /** - * Gets a new and unique Session alias. Typically this will be called to pass into - * {@code HttpSessionManager#encodeURL(java.lang.String)}. For example: - * - * - * String newAlias = httpSessionManager.getNewSessionAlias(request); - * String addAccountUrl = httpSessionManager.encodeURL("./", newAlias); - * - * - * @param request the {@link HttpServletRequest} to get a new alias from - * @return Gets a new and unique Session alias. - */ - String getNewSessionAlias(HttpServletRequest request); -} diff --git a/spring-session-core/src/main/java/org/springframework/session/web/http/HttpSessionStrategy.java b/spring-session-core/src/main/java/org/springframework/session/web/http/HttpSessionStrategy.java index 3c906d5e..3ea06ea7 100644 --- a/spring-session-core/src/main/java/org/springframework/session/web/http/HttpSessionStrategy.java +++ b/spring-session-core/src/main/java/org/springframework/session/web/http/HttpSessionStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package org.springframework.session.web.http; +import java.util.List; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -25,6 +27,7 @@ import org.springframework.session.Session; * A strategy for mapping HTTP request and responses to a {@link Session}. * * @author Rob Winch + * @author Vedran Pavic * @since 1.0 */ public interface HttpSessionStrategy { @@ -36,10 +39,9 @@ public interface HttpSessionStrategy { * * @param request the {@link javax.servlet.http.HttpServletRequest} to obtain the * session id from. Cannot be null. - * @return the {@link javax.servlet.http.HttpServletRequest} to obtain the session id - * from. + * @return the session ids */ - String getRequestedSessionId(HttpServletRequest request); + List getRequestedSessionIds(HttpServletRequest request); /** * This method is invoked when a new session is created and should inform a client @@ -76,4 +78,5 @@ public interface HttpSessionStrategy { * the {@link org.springframework.session.Session} Cannot be null. */ void onInvalidateSession(HttpServletRequest request, HttpServletResponse response); + } diff --git a/spring-session-core/src/main/java/org/springframework/session/web/http/MultiHttpSessionStrategy.java b/spring-session-core/src/main/java/org/springframework/session/web/http/MultiHttpSessionStrategy.java deleted file mode 100644 index 8d297e9d..00000000 --- a/spring-session-core/src/main/java/org/springframework/session/web/http/MultiHttpSessionStrategy.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014-2016 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 javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - *

- * Some {@link HttpSessionStrategy} may also want to further customize - * {@link HttpServletRequest} and {@link HttpServletResponse} objects. For example, - * {@link CookieHttpSessionStrategy} customizes how URL rewriting is done to select which - * session should be used in the event multiple sessions are active. - *

- * - * @author Rob Winch - * @since 1.0 - * @see CookieHttpSessionStrategy - */ -public interface MultiHttpSessionStrategy - extends HttpSessionStrategy, RequestResponsePostProcessor { -} diff --git a/spring-session-core/src/main/java/org/springframework/session/web/http/RequestResponsePostProcessor.java b/spring-session-core/src/main/java/org/springframework/session/web/http/RequestResponsePostProcessor.java deleted file mode 100644 index efe3bbab..00000000 --- a/spring-session-core/src/main/java/org/springframework/session/web/http/RequestResponsePostProcessor.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2014-2016 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 javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Allows customizing the {@link HttpServletRequest} and/or the - * {@link HttpServletResponse}. - * - * @author Rob Winch - * @since 1.0 - */ -public interface RequestResponsePostProcessor { - - /** - * Allows customizing the {@link HttpServletRequest}. - * - * @param request the original {@link HttpServletRequest}. Cannot be null. - * @param response the original {@link HttpServletResponse}. This is NOT the result of - * {@link #wrapResponse(HttpServletRequest, HttpServletResponse)} Cannot be null. . - * @return a non-null {@link HttpServletRequest} - */ - HttpServletRequest wrapRequest(HttpServletRequest request, - HttpServletResponse response); - - /** - * Allows customizing the {@link HttpServletResponse}. - * - * @param request the original {@link HttpServletRequest}. This is NOT the result of - * {@link #wrapRequest(HttpServletRequest, HttpServletResponse)}. Cannot be null. - * @param response the original {@link HttpServletResponse}. Cannot be null. - * @return a non-null {@link HttpServletResponse} - */ - HttpServletResponse wrapResponse(HttpServletRequest request, - HttpServletResponse response); -} diff --git a/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java b/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java index 59e21e6d..4e5795dd 100644 --- a/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java +++ b/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java @@ -51,10 +51,10 @@ import org.springframework.session.SessionRepository; * *
    *
  • The session id is looked up using - * {@link HttpSessionStrategy#getRequestedSessionId(javax.servlet.http.HttpServletRequest)} + * {@link HttpSessionStrategy#getRequestedSessionIds(javax.servlet.http.HttpServletRequest)} * . The default is to look in a cookie named SESSION.
  • - *
  • The session id of newly created {@link org.springframework.session.Session} - * is sent to the client using + *
  • The session id of newly created {@link org.springframework.session.Session} is sent + * to the client using *
  • The client is notified that the session id is no longer valid with * {@link HttpSessionStrategy#onInvalidateSession(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)} *
  • @@ -69,10 +69,11 @@ import org.springframework.session.SessionRepository; * @param the {@link Session} type. * @since 1.0 * @author Rob Winch + * @author Vedran Pavic */ @Order(SessionRepositoryFilter.DEFAULT_ORDER) -public class SessionRepositoryFilter - extends OncePerRequestFilter { +public class SessionRepositoryFilter extends OncePerRequestFilter { + private static final String SESSION_LOGGER_NAME = SessionRepositoryFilter.class .getName().concat(".SESSION_LOGGER"); @@ -102,7 +103,7 @@ public class SessionRepositoryFilter private ServletContext servletContext; - private MultiHttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy(); + private HttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy(); /** * Creates a new instance. @@ -123,21 +124,6 @@ public class SessionRepositoryFilter * @param httpSessionStrategy the {@link HttpSessionStrategy} to use. Cannot be null. */ public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) { - if (httpSessionStrategy == null) { - throw new IllegalArgumentException("httpSessionStrategy cannot be null"); - } - this.httpSessionStrategy = new MultiHttpSessionStrategyAdapter( - httpSessionStrategy); - } - - /** - * Sets the {@link MultiHttpSessionStrategy} to be used. The default is a - * {@link CookieHttpSessionStrategy}. - * - * @param httpSessionStrategy the {@link MultiHttpSessionStrategy} to use. Cannot be - * null. - */ - public void setHttpSessionStrategy(MultiHttpSessionStrategy httpSessionStrategy) { if (httpSessionStrategy == null) { throw new IllegalArgumentException("httpSessionStrategy cannot be null"); } @@ -155,13 +141,8 @@ public class SessionRepositoryFilter SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper( wrappedRequest, response); - HttpServletRequest strategyRequest = this.httpSessionStrategy - .wrapRequest(wrappedRequest, wrappedResponse); - HttpServletResponse strategyResponse = this.httpSessionStrategy - .wrapResponse(wrappedRequest, wrappedResponse); - try { - filterChain.doFilter(strategyRequest, strategyResponse); + filterChain.doFilter(wrappedRequest, wrappedResponse); } finally { wrappedRequest.commitSession(); @@ -213,9 +194,13 @@ public class SessionRepositoryFilter */ private final class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper { + private Boolean requestedSessionIdValid; + private boolean requestedSessionInvalidated; + private final HttpServletResponse response; + private final ServletContext servletContext; private SessionRepositoryRequestWrapper(HttpServletRequest request, @@ -262,6 +247,7 @@ public class SessionRepositoryFilter } } + @Override @SuppressWarnings("unused") public String changeSessionId() { HttpSession session = getSession(false); @@ -313,25 +299,24 @@ public class SessionRepositoryFilter return currentSession; } String requestedSessionId = getRequestedSessionId(); - if (requestedSessionId != null - && getAttribute(INVALID_SESSION_ID_ATTR) == null) { - S session = getSession(requestedSessionId); - if (session != null) { + if (requestedSessionId != null) { + if (getAttribute(INVALID_SESSION_ID_ATTR) == null) { + S session = getSession(requestedSessionId); this.requestedSessionIdValid = true; currentSession = new HttpSessionWrapper(session, getServletContext()); currentSession.setNew(false); setCurrentSession(currentSession); return currentSession; } - else { - // This is an invalid session id. No need to ask again if - // request.getSession is invoked for the duration of this request - if (SESSION_LOGGER.isDebugEnabled()) { - SESSION_LOGGER.debug( - "No session found by id: Caching result for getSession(false) for this HttpServletRequest."); - } - setAttribute(INVALID_SESSION_ID_ATTR, "true"); + } + else { + // This is an invalid session id. No need to ask again if + // request.getSession is invoked for the duration of this request + if (SESSION_LOGGER.isDebugEnabled()) { + SESSION_LOGGER.debug( + "No session found by id: Caching result for getSession(false) for this HttpServletRequest."); } + setAttribute(INVALID_SESSION_ID_ATTR, "true"); } if (!create) { return null; @@ -367,7 +352,10 @@ public class SessionRepositoryFilter @Override public String getRequestedSessionId() { return SessionRepositoryFilter.this.httpSessionStrategy - .getRequestedSessionId(this); + .getRequestedSessionIds(this).stream() + .filter(sessionId -> SessionRepositoryFilter.this.sessionRepository + .findById(sessionId) != null) + .findFirst().orElse(null); } /** @@ -390,44 +378,7 @@ public class SessionRepositoryFilter SessionRepositoryFilter.this.sessionRepository.deleteById(getId()); } } + } - /** - * A delegating implementation of {@link MultiHttpSessionStrategy}. - */ - static class MultiHttpSessionStrategyAdapter implements MultiHttpSessionStrategy { - private HttpSessionStrategy delegate; - - /** - * Create a new {@link MultiHttpSessionStrategyAdapter} instance. - * @param delegate the delegate HTTP session strategy - */ - MultiHttpSessionStrategyAdapter(HttpSessionStrategy delegate) { - this.delegate = delegate; - } - - public String getRequestedSessionId(HttpServletRequest request) { - return this.delegate.getRequestedSessionId(request); - } - - public void onNewSession(Session session, HttpServletRequest request, - HttpServletResponse response) { - this.delegate.onNewSession(session, request, response); - } - - public void onInvalidateSession(HttpServletRequest request, - HttpServletResponse response) { - this.delegate.onInvalidateSession(request, response); - } - - public HttpServletRequest wrapRequest(HttpServletRequest request, - HttpServletResponse response) { - return request; - } - - public HttpServletResponse wrapResponse(HttpServletRequest request, - HttpServletResponse response) { - return response; - } - } } diff --git a/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomCookieSerializerTests.java b/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomCookieSerializerTests.java index b135bd3a..8cd35f42 100644 --- a/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomCookieSerializerTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomCookieSerializerTests.java @@ -17,8 +17,7 @@ package org.springframework.session.config.annotation.web.http; import java.io.IOException; -import java.util.Arrays; -import java.util.concurrent.ConcurrentHashMap; +import java.util.Collections; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -35,8 +34,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.session.MapSessionRepository; +import org.springframework.session.MapSession; import org.springframework.session.Session; +import org.springframework.session.SessionRepository; import org.springframework.session.web.http.CookieSerializer; import org.springframework.session.web.http.CookieSerializer.CookieValue; import org.springframework.session.web.http.SessionRepositoryFilter; @@ -46,6 +46,7 @@ import org.springframework.test.context.web.WebAppConfiguration; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -72,6 +73,9 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests { @Autowired private SessionRepositoryFilter sessionRepositoryFilter; + @Autowired + private SessionRepository sessionRepository; + @Autowired private CookieSerializer cookieSerializer; @@ -84,7 +88,9 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests { public void usesReadSessionIds() throws Exception { String sessionId = "sessionId"; given(this.cookieSerializer.readCookieValues(any(HttpServletRequest.class))) - .willReturn(Arrays.asList(sessionId)); + .willReturn(Collections.singletonList(sessionId)); + given(this.sessionRepository.findById(anyString())) + .willReturn(new MapSession(sessionId)); this.sessionRepositoryFilter.doFilter(this.request, this.response, this.chain); @@ -93,6 +99,8 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests { @Test public void usesWrite() throws Exception { + given(this.sessionRepository.findById(anyString())).willReturn(new MapSession()); + this.sessionRepositoryFilter.doFilter(this.request, this.response, new MockFilterChain() { @@ -116,8 +124,8 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests { static class Config { @Bean - public MapSessionRepository mapSessionRepository() { - return new MapSessionRepository(new ConcurrentHashMap<>()); + public SessionRepository sessionRepository() { + return mock(SessionRepository.class); } @Bean diff --git a/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomMultiHttpSessionStrategyTests.java b/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomMultiHttpSessionStrategyTests.java deleted file mode 100644 index 68cdafbf..00000000 --- a/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomMultiHttpSessionStrategyTests.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2014-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.config.annotation.web.http; - -import java.util.concurrent.ConcurrentHashMap; - -import javax.servlet.http.HttpServletRequest; -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.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.mock.web.MockFilterChain; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.session.MapSessionRepository; -import org.springframework.session.Session; -import org.springframework.session.web.http.MultiHttpSessionStrategy; -import org.springframework.session.web.http.SessionRepositoryFilter; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -/** - * Tests for {@link SpringHttpSessionConfiguration} using a custom - * {@link MultiHttpSessionStrategy}. - * - * @author Rob Winch - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class EnableSpringHttpSessionCustomMultiHttpSessionStrategyTests { - - @Autowired - private MockHttpServletRequest request; - - @Autowired - private MockHttpServletResponse response; - - private MockFilterChain chain; - - @Autowired - private SessionRepositoryFilter sessionRepositoryFilter; - - @Autowired - private MultiHttpSessionStrategy strategy; - - @Before - public void setup() { - this.chain = new MockFilterChain(); - } - - @Test - public void wrapRequestAndResponseUsed() throws Exception { - given(this.strategy.wrapRequest(any(HttpServletRequest.class), - any(HttpServletResponse.class))).willReturn(this.request); - given(this.strategy.wrapResponse(any(HttpServletRequest.class), - any(HttpServletResponse.class))).willReturn(this.response); - - this.sessionRepositoryFilter.doFilter(this.request, this.response, this.chain); - - verify(this.strategy).wrapRequest(any(HttpServletRequest.class), - any(HttpServletResponse.class)); - verify(this.strategy).wrapResponse(any(HttpServletRequest.class), - any(HttpServletResponse.class)); - } - - @EnableSpringHttpSession - @Configuration - static class Config { - - @Bean - public MapSessionRepository mapSessionRepository() { - return new MapSessionRepository(new ConcurrentHashMap<>()); - } - - @Bean - public MultiHttpSessionStrategy strategy() { - return mock(MultiHttpSessionStrategy.class); - } - - } - -} diff --git a/spring-session-core/src/test/java/org/springframework/session/web/http/CookieHttpSessionStrategyTests.java b/spring-session-core/src/test/java/org/springframework/session/web/http/CookieHttpSessionStrategyTests.java index 46f8e02c..73ec78fc 100644 --- a/spring-session-core/src/test/java/org/springframework/session/web/http/CookieHttpSessionStrategyTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/web/http/CookieHttpSessionStrategyTests.java @@ -17,10 +17,9 @@ package org.springframework.session.web.http; import java.util.Base64; -import java.util.Map; +import java.util.Collections; import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; import org.junit.Before; import org.junit.Test; @@ -32,7 +31,11 @@ import org.springframework.session.Session; import static org.assertj.core.api.Assertions.assertThat; +/** + * Tests for {@link CookieHttpSessionStrategy}. + */ public class CookieHttpSessionStrategyTests { + private MockHttpServletRequest request; private MockHttpServletResponse response; @@ -51,22 +54,22 @@ public class CookieHttpSessionStrategyTests { @Test public void getRequestedSessionIdNull() throws Exception { - assertThat(this.strategy.getRequestedSessionId(this.request)).isNull(); + assertThat(this.strategy.getRequestedSessionIds(this.request)).isEmpty(); } @Test public void getRequestedSessionIdNotNull() throws Exception { setSessionCookie(this.session.getId()); - assertThat(this.strategy.getRequestedSessionId(this.request)) - .isEqualTo(this.session.getId()); + assertThat(this.strategy.getRequestedSessionIds(this.request)) + .isEqualTo(Collections.singletonList(this.session.getId())); } @Test public void getRequestedSessionIdNotNullCustomCookieName() throws Exception { setCookieName("CUSTOM"); setSessionCookie(this.session.getId()); - assertThat(this.strategy.getRequestedSessionId(this.request)) - .isEqualTo(this.session.getId()); + assertThat(this.strategy.getRequestedSessionIds(this.request)) + .isEqualTo(Collections.singletonList(this.session.getId())); } @Test @@ -97,46 +100,6 @@ public class CookieHttpSessionStrategyTests { assertThat(base64Decode(cookies[1].getValue())).isEqualTo(newSession.getId()); } - @Test - public void onNewSessionExistingSessionSameAlias() throws Exception { - Session existing = new MapSession(); - setSessionCookie(existing.getId()); - this.strategy.onNewSession(this.session, this.request, this.response); - assertThat(getSessionId()).isEqualTo(this.session.getId()); - } - - @Test - public void onNewSessionExistingSessionNewAlias() throws Exception { - Session existing = new MapSession(); - setSessionCookie(existing.getId()); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new"); - this.strategy.onNewSession(this.session, this.request, this.response); - assertThat(getSessionId()) - .isEqualTo("0 " + existing.getId() + " new " + this.session.getId()); - } - - @Test - public void onNewSessionExistingSessionNewAliasCustomDelimiter() throws Exception { - this.strategy.setSerializationDelimiter("_"); - Session existing = new MapSession(); - setSessionCookie(existing.getId()); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new"); - this.strategy.onNewSession(this.session, this.request, this.response); - assertThat(getSessionId()) - .isEqualTo("0_" + existing.getId() + "_new_" + this.session.getId()); - } - - // gh-321 - @Test - public void onNewSessionExplicitAlias() throws Exception { - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new"); - this.strategy.onNewSession(this.session, this.request, this.response); - assertThat(getSessionId()).isEqualTo("new " + this.session.getId()); - } - @Test public void onNewSessionCookiePath() throws Exception { this.request.setContextPath("/somethingunique"); @@ -177,533 +140,12 @@ public class CookieHttpSessionStrategyTests { assertThat(getSessionId()).isEmpty(); } - @Test - public void onDeleteSessionExistingSessionSameAlias() throws Exception { - Session existing = new MapSession(); - setSessionCookie("0 " + existing.getId() + " new " + this.session.getId()); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new"); - this.strategy.onInvalidateSession(this.request, this.response); - assertThat(getSessionId()).isEqualTo(existing.getId()); - } - - @Test - public void onDeleteSessionExistingSessionNewAlias() throws Exception { - Session existing = new MapSession(); - setSessionCookie("0 " + existing.getId() + " new " + this.session.getId()); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new"); - this.strategy.onInvalidateSession(this.request, this.response); - assertThat(getSessionId()).isEqualTo(existing.getId()); - } - - @Test - public void encodeURLNoExistingQuery() { - assertThat(this.strategy.encodeURL("/url", "2")).isEqualTo("/url?_s=2"); - } - - @Test - public void encodeURLNoExistingQueryEmpty() { - assertThat(this.strategy.encodeURL("/url?", "2")).isEqualTo("/url?_s=2"); - } - - @Test - public void encodeURLExistingQueryNoAlias() { - assertThat(this.strategy.encodeURL("/url?a=b", "2")).isEqualTo("/url?a=b&_s=2"); - } - - @Test - public void encodeURLExistingQueryExistingAliasStart() { - assertThat(this.strategy.encodeURL("/url?_s=1&y=z", "2")) - .isEqualTo("/url?_s=2&y=z"); - } - - @Test - public void encodeURLExistingQueryExistingAliasMiddle() { - assertThat(this.strategy.encodeURL("/url?a=b&_s=1&y=z", "2")) - .isEqualTo("/url?a=b&_s=2&y=z"); - } - - @Test - public void encodeURLExistingQueryExistingAliasEnd() { - assertThat(this.strategy.encodeURL("/url?a=b&_s=1", "2")) - .isEqualTo("/url?a=b&_s=2"); - } - - // - - @Test - public void encodeURLExistingQueryParamEndsWithActualParamStart() { - assertThat(this.strategy.encodeURL("/url?x_s=1&y=z", "2")) - .isEqualTo("/url?x_s=1&y=z&_s=2"); - } - - @Test - public void encodeURLExistingQueryParamEndsWithActualParamMiddle() { - assertThat(this.strategy.encodeURL("/url?a=b&x_s=1&y=z", "2")) - .isEqualTo("/url?a=b&x_s=1&y=z&_s=2"); - } - - @Test - public void encodeURLExistingQueryParamEndsWithActualParamEnd() { - assertThat(this.strategy.encodeURL("/url?a=b&x_s=1", "2")) - .isEqualTo("/url?a=b&x_s=1&_s=2"); - } - - // - - @Test - public void encodeURLNoExistingQueryDefaultAlias() { - assertThat(this.strategy.encodeURL("/url", "0")).isEqualTo("/url"); - } - - @Test - public void encodeURLNoExistingQueryEmptyDefaultAlias() { - assertThat(this.strategy.encodeURL("/url?", "0")).isEqualTo("/url?"); - } - - @Test - public void encodeURLExistingQueryNoAliasDefaultAlias() { - assertThat(this.strategy.encodeURL("/url?a=b", "0")).isEqualTo("/url?a=b"); - } - - @Test - public void encodeURLExistingQueryExistingAliasStartDefaultAlias() { - // relaxed constraint as result /url?&y=z does not hurt anything (ideally should - // remove the &) - assertThat(this.strategy.encodeURL("/url?_s=1&y=z", "0")) - .doesNotContain("_s=0&_s=1"); - } - - @Test - public void encodeURLExistingQueryExistingAliasMiddleDefaultAlias() { - assertThat(this.strategy.encodeURL("/url?a=b&_s=1&y=z", "0")) - .isEqualTo("/url?a=b&y=z"); - } - - @Test - public void encodeURLExistingQueryExistingAliasEndDefaultAlias() { - assertThat(this.strategy.encodeURL("/url?a=b&_s=1", "0")).isEqualTo("/url?a=b"); - } - - @Test - public void encodeURLWithSameAlias() { - String url = String.format("/url?%s=1", - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME); - assertThat(this.strategy.encodeURL(url, "1")).isEqualTo(url); - } - - @Test - public void encodeURLWithSameAliasOtherQueryParamsBefore() { - String url = String.format("/url?a=b&%s=1", - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME); - assertThat(this.strategy.encodeURL(url, "1")).isEqualTo(url); - } - - @Test - public void encodeURLWithSameAliasOtherQueryParamsAfter() { - String url = String.format("/url?%s=1&a=b", - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME); - assertThat(this.strategy.encodeURL(url, "1")).isEqualTo(url); - } - - @Test - public void encodeURLWithSameAliasOtherQueryParamsBeforeAndAfter() { - String url = String.format("/url?a=b&%s=1&c=d", - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME); - assertThat(this.strategy.encodeURL(url, "1")).isEqualTo(url); - } - - @Test - public void encodeURLMaliciousAlias() { - assertThat(this.strategy.encodeURL("/url?a=b&_s=1", - "\"> ")).isEqualTo( - "/url?a=b&_s=%22%3E+%3Cscript%3Ealert%28%27hi%27%29%3C%2Fscript%3E"); - } - - // --- getCurrentSessionAlias - - @Test - public void getCurrentSessionAliasNull() { - assertThat(this.strategy.getCurrentSessionAlias(this.request)) - .isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS); - } - - @Test - public void getCurrentSessionAliasNullParamName() { - this.strategy.setSessionAliasParamName(null); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "NOT USED"); - - assertThat(this.strategy.getCurrentSessionAlias(this.request)) - .isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS); - } - - // protect against malicious users - @Test - public void getCurrentSessionAliasContainsQuote() { - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here\"this"); - - assertThat(this.strategy.getCurrentSessionAlias(this.request)) - .isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS); - } - - @Test - public void getCurrentSessionAliasContainsSingleQuote() { - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here'this"); - - assertThat(this.strategy.getCurrentSessionAlias(this.request)) - .isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS); - } - - @Test - public void getCurrentSessionAliasContainsSpace() { - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here this"); - - assertThat(this.strategy.getCurrentSessionAlias(this.request)) - .isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS); - } - - @Test - public void getCurrentSessionAliasContainsLt() { - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "herethis"); - - assertThat(this.strategy.getCurrentSessionAlias(this.request)) - .isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS); - } - - @Test - public void getCurrentSessionAliasTooLong() { - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, - "012345678901234567890123456789012345678901234567890"); - - assertThat(this.strategy.getCurrentSessionAlias(this.request)) - .isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS); - } - - // We want some sort of length restrictions, but want to ensure some sort of length - // Technically no hard limit, but chose 50 - @Test - public void getCurrentSessionAliasAllows50() { - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, - "01234567890123456789012345678901234567890123456789"); - - assertThat(this.strategy.getCurrentSessionAlias(this.request)) - .isEqualTo("01234567890123456789012345678901234567890123456789"); - } - - @Test - public void getCurrentSession() { - String expectedAlias = "1"; - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, - expectedAlias); - assertThat(this.strategy.getCurrentSessionAlias(this.request)) - .isEqualTo(expectedAlias); - } - - // --- getNewSessionAlias - - @Test - public void getNewSessionAliasNoSessions() { - assertThat(this.strategy.getNewSessionAlias(this.request)) - .isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS); - } - - @Test - public void getNewSessionAliasSingleSession() { - setSessionCookie("abc"); - - assertThat(this.strategy.getNewSessionAlias(this.request)).isEqualTo("1"); - } - - @Test - public void getNewSessionAlias2Sessions() { - setCookieWithNSessions(2); - - assertThat(this.strategy.getNewSessionAlias(this.request)).isEqualTo("2"); - } - - @Test - public void getNewSessionAlias9Sessions() { - setCookieWithNSessions(9); - - assertThat(this.strategy.getNewSessionAlias(this.request)) - .isEqualToIgnoringCase("9"); - } - - @Test - public void getNewSessionAlias10Sessions() { - setCookieWithNSessions(10); - - assertThat(this.strategy.getNewSessionAlias(this.request)) - .isEqualToIgnoringCase("a"); - } - - @Test - public void getNewSessionAlias16Sessions() { - setCookieWithNSessions(16); - - assertThat(this.strategy.getNewSessionAlias(this.request)) - .isEqualToIgnoringCase("10"); - } - - @Test - public void getNewSessionAliasInvalidAlias() { - setSessionCookie("0 1 $ b"); - - assertThat(this.strategy.getNewSessionAlias(this.request)) - .isEqualToIgnoringCase("1"); - } - - // --- getSessionIds - - @Test - public void getSessionIdsNone() { - assertThat(this.strategy.getSessionIds(this.request)).isEmpty(); - } - - @Test - public void getSessionIdsSingle() { - String expectedId = "a"; - setSessionCookie(expectedId); - - Map sessionIds = this.strategy.getSessionIds(this.request); - assertThat(sessionIds.size()).isEqualTo(1); - assertThat(sessionIds.get("0")).isEqualTo(expectedId); - } - - @Test - public void getSessionIdsMulti() { - setSessionCookie("0 a 1 b"); - - Map sessionIds = this.strategy.getSessionIds(this.request); - assertThat(sessionIds.size()).isEqualTo(2); - assertThat(sessionIds.get("0")).isEqualTo("a"); - assertThat(sessionIds.get("1")).isEqualTo("b"); - } - - @Test - public void getSessionIdsMultiCustomDelimeter() { - this.strategy.setDeserializationDelimiter("_"); - setSessionCookie("0_a_1_b"); - - Map sessionIds = this.strategy.getSessionIds(this.request); - assertThat(sessionIds.size()).isEqualTo(2); - assertThat(sessionIds.get("0")).isEqualTo("a"); - assertThat(sessionIds.get("1")).isEqualTo("b"); - } - - @Test - public void getSessionIdsMultiCustomDelimeterMigration() { - this.strategy.setDeserializationDelimiter("_ "); - this.strategy.setSerializationDelimiter("_"); - - // can parse the old way - setSessionCookie("0 a 1 b"); - - Map sessionIds = this.strategy.getSessionIds(this.request); - assertThat(sessionIds.size()).isEqualTo(2); - assertThat(sessionIds.get("0")).isEqualTo("a"); - assertThat(sessionIds.get("1")).isEqualTo("b"); - - // can parse the new way - this.request = new MockHttpServletRequest(); - this.response = new MockHttpServletResponse(); - setSessionCookie("0_a_1_b"); - - sessionIds = this.strategy.getSessionIds(this.request); - assertThat(sessionIds.size()).isEqualTo(2); - assertThat(sessionIds.get("0")).isEqualTo("a"); - assertThat(sessionIds.get("1")).isEqualTo("b"); - - // writes the new way - this.request = new MockHttpServletRequest(); - this.response = new MockHttpServletResponse(); - Session existing = new MapSession(); - setSessionCookie(existing.getId()); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new"); - this.strategy.onNewSession(this.session, this.request, this.response); - assertThat(getSessionId()) - .isEqualTo("0_" + existing.getId() + "_new_" + this.session.getId()); - - } - - @Test - public void getSessionIdsDangling() { - setSessionCookie("0 a 1 b noValue"); - - Map sessionIds = this.strategy.getSessionIds(this.request); - assertThat(sessionIds.size()).isEqualTo(2); - assertThat(sessionIds.get("0")).isEqualTo("a"); - assertThat(sessionIds.get("1")).isEqualTo("b"); - } - - // --- helper - @Test public void createSessionCookieValue() { assertThat(createSessionCookieValue(17)).isEqualToIgnoringCase( "0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 a 10 b 11 c 12 d 13 e 14 f 15 10 16"); } - @Test - public void responseEncodeRedirectUrlWhereRedirectUrlDoesntContainAliasCurrentReqNoAlias() { - String url = "http://www.somehost.com/some/path"; - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedRedirectUrl).isEqualTo(url); - } - - @Test - public void responseEncodeRedirectUrlWhereRedirectUrlDoesntContainAliasCurrentReqHasAlias() { - String url = "http://www.somehost.com/some/path"; - String alias = "1"; - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias); - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedRedirectUrl).isEqualTo(String.format("%s?%s=%s", url, - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias)); - } - - @Test - public void responseEncodeRedirectUrlWhereRedirectUrlContainsAliasCurrentReqHasNoAlias() { - String url = String.format("http://www.somehost.com/some/path?%s=5", - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "4"); - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedRedirectUrl).isEqualTo(url); - } - - @Test - public void responseEncodeRedirectUrlWhereRedirectUrlDoesntContainAliasCurrentReqNoAliasWithOtherParams() { - String url = "http://www.somehost.com/some/path?a=b"; - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedRedirectUrl).isEqualTo(url); - } - - @Test - public void responseEncodeRedirectUrlWhereRedirectUrlDoesntContainAliasCurrentReqHasAliasWithOtherParams() { - String url = "http://www.somehost.com/some/path?a=b"; - String alias = "1"; - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias); - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedRedirectUrl).isEqualTo(String.format("%s&%s=%s", url, - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias)); - } - - @Test - public void responseEncodeRedirectUrlWhereRedirectUrlContainsAliasCurrentReqHasNoAliasWithOtherParams() { - String url = String.format("http://www.somehost.com/some/path?a=b&%s=5&c=d", - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "4"); - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedRedirectUrl).isEqualTo(url); - } - - @Test - public void responseEncodeUrlWhereRedirectUrlDoesntContainAliasCurrentReqNoAlias() { - String url = "http://www.somehost.com/some/path"; - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedUrl).isEqualTo(url); - } - - @Test - public void responseEncodeUrlWhereRedirectUrlDoesntContainAliasCurrentReqHasAlias() { - String url = "http://www.somehost.com/some/path"; - String alias = "1"; - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias); - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedUrl).isEqualTo(String.format("%s?%s=%s", url, - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias)); - } - - @Test - public void responseEncodeUrlWhereRedirectUrlContainsAliasCurrentReqHasNoAlias() { - String url = String.format("http://www.somehost.com/some/path?%s=5", - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "4"); - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedUrl).isEqualTo(url); - } - - @Test - public void responseEncodeUrlWhereRedirectUrlDoesntContainAliasCurrentReqNoAliasWithOtherParams() { - String url = "http://www.somehost.com/some/path?a=b"; - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedUrl).isEqualTo(url); - } - - @Test - public void responseEncodeUrlWhereRedirectUrlDoesntContainAliasCurrentReqHasAliasWithOtherParams() { - String url = "http://www.somehost.com/some/path?a=b"; - String alias = "1"; - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias); - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedUrl).isEqualTo(String.format("%s&%s=%s", url, - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias)); - } - - @Test - public void responseEncodeUrlWhereRedirectUrlContainsAliasCurrentReqHasNoAliasWithOtherParams() { - String url = String.format("http://www.somehost.com/some/path?a=b&%s=5&c=d", - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME); - this.request.setParameter( - CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "4"); - HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request, - this.response); - String encodedUrl = wrappedResponse.encodeRedirectURL(url); - assertThat(encodedUrl).isEqualTo(url); - } - - private void setCookieWithNSessions(long size) { - setSessionCookie(createSessionCookieValue(size)); - } - private String createSessionCookieValue(long size) { StringBuilder sb = new StringBuilder(); @@ -720,18 +162,18 @@ public class CookieHttpSessionStrategyTests { return sb.toString(); } - public void setCookieName(String cookieName) { + private void setCookieName(String cookieName) { DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer(); cookieSerializer.setCookieName(cookieName); this.strategy.setCookieSerializer(cookieSerializer); this.cookieName = cookieName; } - public void setSessionCookie(String value) { + private void setSessionCookie(String value) { this.request.setCookies(new Cookie(this.cookieName, base64Encode(value))); } - public String getSessionId() { + private String getSessionId() { return base64Decode(this.response.getCookie(this.cookieName).getValue()); } diff --git a/spring-session-core/src/test/java/org/springframework/session/web/http/HeaderSessionStrategyTests.java b/spring-session-core/src/test/java/org/springframework/session/web/http/HeaderSessionStrategyTests.java index 91eaafcf..c21e5f13 100644 --- a/spring-session-core/src/test/java/org/springframework/session/web/http/HeaderSessionStrategyTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/web/http/HeaderSessionStrategyTests.java @@ -16,6 +16,8 @@ package org.springframework.session.web.http; +import java.util.Collections; + import org.junit.Before; import org.junit.Test; @@ -26,6 +28,9 @@ import org.springframework.session.Session; import static org.assertj.core.api.Assertions.assertThat; +/** + * Tests for {@link HeaderHttpSessionStrategy}. + */ public class HeaderSessionStrategyTests { private MockHttpServletRequest request; @@ -46,22 +51,22 @@ public class HeaderSessionStrategyTests { @Test public void getRequestedSessionIdNull() throws Exception { - assertThat(this.strategy.getRequestedSessionId(this.request)).isNull(); + assertThat(this.strategy.getRequestedSessionIds(this.request)).isEmpty(); } @Test public void getRequestedSessionIdNotNull() throws Exception { setSessionId(this.session.getId()); - assertThat(this.strategy.getRequestedSessionId(this.request)) - .isEqualTo(this.session.getId()); + assertThat(this.strategy.getRequestedSessionIds(this.request)) + .isEqualTo(Collections.singletonList(this.session.getId())); } @Test public void getRequestedSessionIdNotNullCustomHeaderName() throws Exception { setHeaderName("CUSTOM"); setSessionId(this.session.getId()); - assertThat(this.strategy.getRequestedSessionId(this.request)) - .isEqualTo(this.session.getId()); + assertThat(this.strategy.getRequestedSessionIds(this.request)) + .isEqualTo(Collections.singletonList(this.session.getId())); } @Test @@ -116,16 +121,16 @@ public class HeaderSessionStrategyTests { this.strategy.setHeaderName(null); } - public void setHeaderName(String headerName) { + private void setHeaderName(String headerName) { this.strategy.setHeaderName(headerName); this.headerName = headerName; } - public void setSessionId(String id) { + private void setSessionId(String id) { this.request.addHeader(this.headerName, id); } - public String getSessionId() { + private String getSessionId() { return this.response.getHeader(this.headerName); } diff --git a/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java b/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java index 49100ad5..00378b33 100644 --- a/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java @@ -60,12 +60,12 @@ import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -95,8 +95,7 @@ public class SessionRepositoryFilterTests { public void setup() throws Exception { this.sessions = new HashMap<>(); this.sessionRepository = new MapSessionRepository(this.sessions); - this.filter = new SessionRepositoryFilter<>( - this.sessionRepository); + this.filter = new SessionRepositoryFilter<>(this.sessionRepository); setupRequest(); } @@ -134,8 +133,7 @@ public class SessionRepositoryFilterTests { session.setLastAccessedTime(Instant.EPOCH); this.sessionRepository = spy(this.sessionRepository); given(this.sessionRepository.createSession()).willReturn(session); - this.filter = new SessionRepositoryFilter<>( - this.sessionRepository); + this.filter = new SessionRepositoryFilter<>(this.sessionRepository); doFilter(new DoInFilter() { @Override @@ -240,8 +238,7 @@ public class SessionRepositoryFilterTests { @Test public void doFilterServletContextExplicit() throws Exception { final ServletContext expectedContext = new MockServletContext(); - this.filter = new SessionRepositoryFilter<>( - this.sessionRepository); + this.filter = new SessionRepositoryFilter<>(this.sessionRepository); this.filter.setServletContext(expectedContext); doFilter(new DoInFilter() { @@ -431,8 +428,7 @@ public class SessionRepositoryFilterTests { return createSession(); } }; - this.filter = new SessionRepositoryFilter<>( - this.sessionRepository); + this.filter = new SessionRepositoryFilter<>(this.sessionRepository); doFilter(new DoInFilter() { @Override public void doFilter(HttpServletRequest wrappedRequest) { @@ -568,7 +564,7 @@ public class SessionRepositoryFilterTests { ReflectionTestUtils.invokeMethod(wrappedRequest, "changeSessionId"); fail("Exected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -674,7 +670,7 @@ public class SessionRepositoryFilterTests { sessionContext.getIds().nextElement(); fail("Expected Exception"); } - catch (NoSuchElementException success) { + catch (NoSuchElementException ignored) { } } }); @@ -725,7 +721,7 @@ public class SessionRepositoryFilterTests { session.invalidate(); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -742,7 +738,7 @@ public class SessionRepositoryFilterTests { session.getCreationTime(); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -759,7 +755,7 @@ public class SessionRepositoryFilterTests { session.getAttribute("attr"); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -776,7 +772,7 @@ public class SessionRepositoryFilterTests { session.getValue("attr"); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -793,7 +789,7 @@ public class SessionRepositoryFilterTests { session.getAttributeNames(); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -810,7 +806,7 @@ public class SessionRepositoryFilterTests { session.getValueNames(); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -827,7 +823,7 @@ public class SessionRepositoryFilterTests { session.setAttribute("a", "b"); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -844,7 +840,7 @@ public class SessionRepositoryFilterTests { session.putValue("a", "b"); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -861,7 +857,7 @@ public class SessionRepositoryFilterTests { session.removeAttribute("name"); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -878,7 +874,7 @@ public class SessionRepositoryFilterTests { session.removeValue("name"); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -895,7 +891,7 @@ public class SessionRepositoryFilterTests { session.isNew(); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -912,7 +908,7 @@ public class SessionRepositoryFilterTests { session.getLastAccessedTime(); fail("Expected Exception"); } - catch (IllegalStateException success) { + catch (IllegalStateException ignored) { } } }); @@ -1055,8 +1051,9 @@ public class SessionRepositoryFilterTests { HttpServletResponse wrappedResponse) throws IOException { String id = wrappedRequest.getSession().getId(); wrappedResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .findById(id)).isNotNull(); + assertThat( + SessionRepositoryFilterTests.this.sessionRepository.findById(id)) + .isNotNull(); } }); } @@ -1070,8 +1067,9 @@ public class SessionRepositoryFilterTests { String id = wrappedRequest.getSession().getId(); wrappedResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error"); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .findById(id)).isNotNull(); + assertThat( + SessionRepositoryFilterTests.this.sessionRepository.findById(id)) + .isNotNull(); } }); } @@ -1084,8 +1082,9 @@ public class SessionRepositoryFilterTests { HttpServletResponse wrappedResponse) throws IOException { String id = wrappedRequest.getSession().getId(); wrappedResponse.sendRedirect("/"); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .findById(id)).isNotNull(); + assertThat( + SessionRepositoryFilterTests.this.sessionRepository.findById(id)) + .isNotNull(); } }); } @@ -1098,8 +1097,9 @@ public class SessionRepositoryFilterTests { HttpServletResponse wrappedResponse) throws IOException { String id = wrappedRequest.getSession().getId(); wrappedResponse.flushBuffer(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .findById(id)).isNotNull(); + assertThat( + SessionRepositoryFilterTests.this.sessionRepository.findById(id)) + .isNotNull(); } }); } @@ -1112,8 +1112,9 @@ public class SessionRepositoryFilterTests { HttpServletResponse wrappedResponse) throws IOException { String id = wrappedRequest.getSession().getId(); wrappedResponse.getOutputStream().flush(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .findById(id)).isNotNull(); + assertThat( + SessionRepositoryFilterTests.this.sessionRepository.findById(id)) + .isNotNull(); } }); } @@ -1126,8 +1127,9 @@ public class SessionRepositoryFilterTests { HttpServletResponse wrappedResponse) throws IOException { String id = wrappedRequest.getSession().getId(); wrappedResponse.getOutputStream().close(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .findById(id)).isNotNull(); + assertThat( + SessionRepositoryFilterTests.this.sessionRepository.findById(id)) + .isNotNull(); } }); } @@ -1140,8 +1142,9 @@ public class SessionRepositoryFilterTests { HttpServletResponse wrappedResponse) throws IOException { String id = wrappedRequest.getSession().getId(); wrappedResponse.getWriter().flush(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .findById(id)).isNotNull(); + assertThat( + SessionRepositoryFilterTests.this.sessionRepository.findById(id)) + .isNotNull(); } }); } @@ -1154,20 +1157,28 @@ public class SessionRepositoryFilterTests { HttpServletResponse wrappedResponse) throws IOException { String id = wrappedRequest.getSession().getId(); wrappedResponse.getWriter().close(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .findById(id)).isNotNull(); + assertThat( + SessionRepositoryFilterTests.this.sessionRepository.findById(id)) + .isNotNull(); } }); } - // --- MultiHttpSessionStrategyAdapter + // --- HttpSessionStrategy @Test public void doFilterAdapterGetRequestedSessionId() throws Exception { + SessionRepository sessionRepository = spy( + new MapSessionRepository(new ConcurrentHashMap<>())); + + this.filter = new SessionRepositoryFilter<>(sessionRepository); this.filter.setHttpSessionStrategy(this.strategy); - final String expectedId = "MultiHttpSessionStrategyAdapter-requested-id"; - given(this.strategy.getRequestedSessionId(any(HttpServletRequest.class))) - .willReturn(expectedId); + final String expectedId = "HttpSessionStrategy-requested-id"; + + given(this.strategy.getRequestedSessionIds(any(HttpServletRequest.class))) + .willReturn(Collections.singletonList(expectedId)); + given(sessionRepository.findById(anyString())) + .willReturn(new MapSession(expectedId)); doFilter(new DoInFilter() { @Override @@ -1211,8 +1222,8 @@ public class SessionRepositoryFilterTests { HttpServletRequest request = (HttpServletRequest) this.chain.getRequest(); String id = request.getSession().getId(); - given(this.strategy.getRequestedSessionId(any(HttpServletRequest.class))) - .willReturn(id); + given(this.strategy.getRequestedSessionIds(any(HttpServletRequest.class))) + .willReturn(Collections.singletonList(id)); setupRequest(); doFilter(new DoInFilter() { @@ -1243,8 +1254,8 @@ public class SessionRepositoryFilterTests { HttpServletRequest request = (HttpServletRequest) this.chain.getRequest(); String id = request.getSession().getId(); - given(this.strategy.getRequestedSessionId(any(HttpServletRequest.class))) - .willReturn(id); + given(this.strategy.getRequestedSessionIds(any(HttpServletRequest.class))) + .willReturn(Collections.singletonList(id)); doFilter(new DoInFilter() { @Override @@ -1340,52 +1351,7 @@ public class SessionRepositoryFilterTests { @Test(expected = IllegalArgumentException.class) public void setHttpSessionStrategyNull() { - this.filter.setHttpSessionStrategy((HttpSessionStrategy) null); - } - - @Test(expected = IllegalArgumentException.class) - public void setMultiHttpSessionStrategyNull() { - this.filter.setHttpSessionStrategy((MultiHttpSessionStrategy) null); - } - - @Test - public void getSessionFalseWithInvalidSessionIdShouldOnlyAskRepositoryOnce() - throws ServletException, IOException { - this.sessionRepository = spy(this.sessionRepository); - this.filter = new SessionRepositoryFilter<>( - this.sessionRepository); - - final String nonExistantSessionId = "nonExistantSessionId"; - setSessionCookie(nonExistantSessionId); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - // Before first invocation - assertThat(SessionRepositoryFilterTests.this.request - .getAttribute(SessionRepositoryFilter.INVALID_SESSION_ID_ATTR)) - .isNull(); - - // First call should go all the way through to the sessioRepository (it - // will not find the session) - HttpSession session = wrappedRequest.getSession(false); - verify(SessionRepositoryFilterTests.this.sessionRepository, times(1)) - .findById(nonExistantSessionId); - assertThat(session).isNull(); - assertThat(SessionRepositoryFilterTests.this.request - .getAttribute(SessionRepositoryFilter.INVALID_SESSION_ID_ATTR)) - .isNotNull(); - - // Second call should not reach the sessionRepository - session = wrappedRequest.getSession(false); - verify(SessionRepositoryFilterTests.this.sessionRepository, times(1)) - .findById(nonExistantSessionId); // still only called once - assertThat(session).isNull(); - assertThat(SessionRepositoryFilterTests.this.request - .getAttribute(SessionRepositoryFilter.INVALID_SESSION_ID_ATTR)) - .isNotNull(); - } - }); + this.filter.setHttpSessionStrategy(null); } // --- helper methods @@ -1435,10 +1401,8 @@ public class SessionRepositoryFilterTests { nameToCookie.put(cookie.getName(), cookie); } } - if (this.response.getCookies() != null) { - for (Cookie cookie : this.response.getCookies()) { - nameToCookie.put(cookie.getName(), cookie); - } + for (Cookie cookie : this.response.getCookies()) { + nameToCookie.put(cookie.getName(), cookie); } Cookie[] nextRequestCookies = new ArrayList<>(nameToCookie.values()) .toArray(new Cookie[0]); @@ -1448,7 +1412,6 @@ public class SessionRepositoryFilterTests { this.request.setCookies(nextRequestCookies); } - @SuppressWarnings("serial") private void doFilter(final DoInFilter doInFilter) throws ServletException, IOException { this.chain = new MockFilterChain(new HttpServlet() { @@ -1456,7 +1419,7 @@ public class SessionRepositoryFilterTests { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { + throws ServletException, IOException { doInFilter.doFilter(request, response); } }); @@ -1471,21 +1434,25 @@ public class SessionRepositoryFilterTests { return new String(Base64.getDecoder().decode(value)); } - abstract class DoInFilter { + private static class SessionRepositoryFilterDefaultOrder implements Ordered { + + public int getOrder() { + return SessionRepositoryFilter.DEFAULT_ORDER; + } + + } + + private abstract class DoInFilter { + void doFilter(HttpServletRequest wrappedRequest, HttpServletResponse wrappedResponse) - throws ServletException, IOException { + throws ServletException, IOException { doFilter(wrappedRequest); } void doFilter(HttpServletRequest wrappedRequest) { } - } - static class SessionRepositoryFilterDefaultOrder implements Ordered { - public int getOrder() { - return SessionRepositoryFilter.DEFAULT_ORDER; - } } }